标题:一个神奇的问题和它的答案
只看楼主
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
得分:0 
回复 20楼 cosdos
嗯,也有这种可能

重剑无锋,大巧不工
2013-11-27 23:03
未来ken
Rank: 2
等 级:论坛游民
帖 子:102
专家分:96
注 册:2013-11-16
得分:7 
好厉害死的说......

任重而道远
2013-11-27 23:57
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
得分:7 
程序代码:
; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.61030.0 

    TITLE    D:\Projects\test\Project9\Project9\main.cpp
    .686P
    .XMM
    include listing.inc
    .model    flat

INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES

PUBLIC    _main
PUBLIC    ??_C@_05LCCCBGPN@True?6?$AA@            ; `string'
EXTRN    __imp__printf_s:PROC
EXTRN    __imp___getch:PROC
EXTRN    __RTC_CheckEsp:PROC
EXTRN    __RTC_InitBase:PROC
EXTRN    __RTC_Shutdown:PROC
EXTRN    __fltused:DWORD
;    COMDAT rtc$TMZ
rtc$TMZ    SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ    ENDS
;    COMDAT rtc$IMZ
rtc$IMZ    SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
rtc$IMZ    ENDS
;    COMDAT ??_C@_05LCCCBGPN@True?6?$AA@
CONST    SEGMENT
??_C@_05LCCCBGPN@True?6?$AA@ DB 'True', 0aH, 00H    ; `string'
CONST    ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; File d:\projects\test\project9\project9\main.cpp
;    COMDAT _main
_TEXT    SEGMENT
_n$ = -8                        ; size = 4
_main    PROC                        ; COMDAT

; 5    : {

    push    ebp
    mov    ebp, esp
    sub    esp, 204                ; 000000ccH
    push    ebx
    push    esi
    push    edi
    lea    edi, DWORD PTR [ebp-204]
    mov    ecx, 51                    ; 00000033H
    mov    eax, -858993460                ; ccccccccH
    rep stosd

; 6    :     int n = 0x80000000;

    mov    DWORD PTR _n$[ebp], -2147483648        ; 80000000H

; 7    :
; 8    :     if (n == (int)(float) n)

    cvtsi2ss xmm0, DWORD PTR _n$[ebp]
    cvttss2si eax, xmm0
    cmp    DWORD PTR _n$[ebp], eax
    jne    SHORT $LN1@main

; 9    :     {
; 10   :         printf_s("True\n");

    mov    esi, esp
    push    OFFSET ??_C@_05LCCCBGPN@True?6?$AA@
    call    DWORD PTR __imp__printf_s
    add    esp, 4
    cmp    esi, esp
    call    __RTC_CheckEsp
$LN1@main:

; 11   :     }
; 12   :     _getch();

    mov    esi, esp
    call    DWORD PTR __imp___getch
    cmp    esi, esp
    call    __RTC_CheckEsp

; 13   : }

    xor    eax, eax
    pop    edi
    pop    esi
    pop    ebx
    add    esp, 204                ; 000000ccH
    cmp    ebp, esp
    call    __RTC_CheckEsp
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP
_TEXT    ENDS
END

    cvtsi2ss xmm0, DWORD PTR _n$[ebp]
    cvttss2si eax, xmm0
~~~~~~~~~~~~~~~~~~
int與float的轉換,使用寄存器的低雙字節,若int本身是32位的,那麼無論怎麼轉,都是不變。

[ 本帖最后由 TonyDeng 于 2013-11-28 11:46 编辑 ]

授人以渔,不授人以鱼。
2013-11-28 11:43
zxc520
Rank: 1
等 级:新手上路
帖 子:4
专家分:7
注 册:2013-11-28
得分:7 
2013-11-28 11:47
peach5460
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:武汉
等 级:贵宾
威 望:30
帖 子:2780
专家分:6060
注 册:2008-1-28
得分:7 
个人认为
只要是个int都行吧

我没试过...

我总觉得授人以鱼不如授人以渔...
可是总有些SB叫嚣着:要么给代码给答案,要么滚蛋...
虽然我知道不要跟SB一般见识,但是我真的没修炼到宠辱不惊...
2013-11-28 14:17
so_love
Rank: 13Rank: 13Rank: 13Rank: 13
等 级:蒙面侠
威 望:7
帖 子:812
专家分:4151
注 册:2013-11-25
得分:7 
n只是个地址啊。怎么转换地址都不会变的。。。所以一直都是true

一花一世界、一叶一追寻、片片花叶落、情系何人身。
2013-11-28 14:49
lleon
Rank: 2
等 级:论坛游民
帖 子:25
专家分:43
注 册:2013-10-28
得分:7 
还是要看精度,假如float只有6位精度,那么123456789转成float就是123456000.0,再转加int得到123456000与原来的n不等。
2013-11-28 16:02
toofunny
Rank: 4
等 级:业余侠客
帖 子:71
专家分:200
注 册:2012-7-22
得分:7 
回复 23楼 TonyDeng
程序代码:
#include <stdio.h>


//精度损失
void demo1(  )
{
    int n = 0;
    float f = n ;
//    float f = n ;汇编代码
//    fild    DWORD PTR _n$[ebp]    ;把n的值放到浮点寄存器( 80位 ), 远大于 32bits,精度无损
//    fstp    DWORD PTR _f$[ebp]    ;这里把浮点寄存器( 80位 )的值返回到变量f( 32位 ),造成精度损失
//    原因:float变量内存结构:1bit(符号位) 8bits(指数位) 23bits(尾数位)
//    当 n有效位 > 24bits 时,尾数丢失
    if (n==(int)f)            //上面 n = 0; n< 24bits, 因此精度无损,输出TRUE
        printf("TRUE\n");
    else
        printf("Flase\n");
   
    n = 0x1ffffff ;//这里 n为25bits , 且超出24bits部分不为0
    f = n ;
    if (n==(int)f)            //这里 n为25bits , n> 24bits, 因此精度丢失,输出Flase
        printf("TRUE\n");
    else
        printf("Flase\n");

    n = 0x1fffff0 ;//这里 n为25bits , 且最后4bit为0 , 丢失后与丢失前相同(都是零)
    f = n ;
    if (n==(int)f)            // 因此精度丢失,但丢失前后相同,输出TRUE
        printf("TRUE\n");
    else
        printf("Flase\n");
}

//精度无损
void demo2(  )
{
    int n;
    if (n==(int)(float)n) 
    //反汇编代码
    //fild    DWORD PTR _n$[ebp]  ;把n的值放到浮点寄存器( 80位 ), 远大于 32bits,精度无损 
    //    call    __ftol            ;把浮点寄存器的值放到eax , 精度无损,原因:eax就是无符号整型
   //    cmp    DWORD PTR _n$[ebp], eax    ;将n的值与eax比较,恒相等。
        printf("TRUE");            //输出True
    else
        printf("Flase");
}

int main(  )
{
    demo1(  );
    demo2(  );
    return 0;
}
测试结果:TRUE FALSE TRUE TRUE
综上所述,LZ的表述其实是个误会。LZ也许认为
int n;
if (n==(int)(float)n)  
等同于
int n = 0;
float f = n ;
if (n==(int)f)
,实际上,对于前者来说,
编译器并没有用一个float单元来保存(float)n的值,因此n==(int)(float)n恒为真。


[ 本帖最后由 toofunny 于 2013-11-29 00:02 编辑 ]
2013-11-28 23:48
qq404380
Rank: 2
等 级:论坛游民
帖 子:32
专家分:53
注 册:2012-7-23
得分:7 
现在的编译器有优化的,会自动处理
2013-11-29 00:08
toofunny
Rank: 4
等 级:业余侠客
帖 子:71
专家分:200
注 册:2012-7-22
得分:0 
最后,应一位网友的要求,我再总结一下哈。
(基于32位机器,vc6,debug版本,未开启优化选项)
-------------------------
对于代码段
    int n;
    if (n==(int)(float)n)  
        printf("TRUE");   
    else
        printf("Flase");
恒输出TRUE
-------------------------
对于代码段
    int n;
    float f = n ;
    if (n==(int)f)  
        printf("TRUE");   
    else
        printf("Flase");
有三种情况
1. n<0x1000001 时 , 转化为浮点数时没有丢失精度,程序输出TRUE

2. n>=0x1000001 时 ,可以分两种情况
    2.1 从第一位有效数字开始,从左往右数24位(二进制位),大于24位的将被抛弃。
       如果被抛弃的都是0 ,则抛弃前后没有影响,因为还原后还是0 , 程序输出TRUE

    2.2 如果被抛弃的数据中含有1 ,则因为还原后都是0 ,
       所以造成n的低位与(int)f的低位不相等,程序输出False。
测试代码:
程序代码:
#include <stdio.h>

int main(  )
{
    //恒输出TRUE
    int n;
    if (n==(int)(float)n) 
        printf("TRUE\n");   
    else
        printf("False\n");
   
    //三种情况
    //1. n<0x1000001 时 , 转化为浮点数时没有丢失精度,程序输出TRUE
    n = 5 ;
    float f = n ;
    if (n==(int)f) 
        printf("TRUE\n");   
    else
        printf("False\n");

//    2. n>=0x1000001 时 ,可以分两种情况
//    2.1 从左往右数24位,大于24位的将被抛弃。
//       如果被抛弃的都是0 ,则抛弃前后没有影响,因为还原后还是0 , 程序输出TRUE
    n = 0x1000010 ;
    f = n ;
    if (n==(int)f) 
        printf("TRUE\n");   
    else
        printf("False\n");

//    2.2 如果被抛弃的数据中含有1 ,则因为还原后都是0 ,
//       所以造成n的低位与(int)f的低位不相等,程序输出False。
    n = 0x1000001 ;
    f = n ;
    if (n==(int)f) 
        printf("TRUE\n");   
    else
        printf("False\n");
    return 0;
}

最后提示:如果编译器智能优化,则两种代码段都是只输出TRUE.按人的逻辑来讲,也是只应该输出TRUE。

[ 本帖最后由 toofunny 于 2013-11-29 02:52 编辑 ]
2013-11-29 02:43



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-424309-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.048075 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved