【散分】VS和CB输出结果不一致

nomasp
博客专家认证
2016-01-11 09:25:19


应该能看清的吧?我把代码再贴一遍:


#include <iostream>
#include <cmath>
using namespace std;

int titleToNumber(string s) {
int n = 0, len = s.length();
for(int i = 0; i < s.length(); ++ i) {
char c = s[i];
int chara = c - 'A' + 1;
cout<<"chara = " << chara << endl;
n += chara * pow(26, len - 1 - i);
cout<<"pow = " << pow(26.0, len - 1 - i) << endl;
cout<<"n = " << n << endl;
cout<<endl;
}
return n;
}

int main() {
cout<<titleToNumber("AAB");
return 0;
}


有人说是因为cmath和math.h的原因,但是我在VS和CB中不论用哪个结果都分别是704和703,其中正确结果是704.

也有人说是因为没有转换成double,但是我在CB中转换之后结果反而成了702.

那么到底是为什么呢?求解答,求各种深入剖析,谢谢。

是散分没错,不过我级别不够只能发100分的了,莫怪……
...全文
470 26 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
引用 21 楼 NoMasp 的回复:
[quote=引用 19 楼 paschen 的回复:] 另外,n += chara * pow(26, len - 1 - i);我猜可能匹配了pow的整数版的浮点计算了,因为26和len-1-i都是整数,如果你改成: n += chara * pow(26.0, len - 1 - i); 算出来也是正确的
嗯嗯,不过加上.0在我CB上还是703,不过已经不重要了,还是应该早点去补补汇编等,谢啦[/quote] 加上后我这CB最后结果就是704了,一切后VS一样了
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 19 楼 paschen 的回复:
另外,n += chara * pow(26, len - 1 - i);我猜可能匹配了pow的整数版的浮点计算了,因为26和len-1-i都是整数,如果你改成: n += chara * pow(26.0, len - 1 - i); 算出来也是正确的
嗯嗯,不过加上.0在我CB上还是703,不过已经不重要了,还是应该早点去补补汇编等,谢啦
paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
从CB的汇编call 0x467cf4 <std::pow<int, int>(int, int)> 得知使用的是int版的pow

paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
另外,n += chara * pow(26, len - 1 - i);我猜可能匹配了pow的整数版的浮点计算了,因为26和len-1-i都是整数,如果你改成: n += chara * pow(26.0, len - 1 - i); 算出来也是正确的
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 15 楼 zhao4zhong1 的回复:
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!) VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
感谢赵老师的解答,我已截图保存 非常感谢。 一开始您给的学习路线图很赞,也反应了我这课程的各种不合理:一开始大一就是C++,没有C也没有计算机导论;然后大二是数据结构和数据库;大三是操作系统、组成原理、计算机网络;大四没课。 要好好补补汇编、编译原理、正则这些了。
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 14 楼 paschen 的回复:
[quote=引用 12 楼 NoMasp 的回复:] [quote=引用 9 楼 paschen 的回复:] 这句 n += chara * pow(26, len - 1 - i); 改成 n += chara * round(pow(26, len - 1 - i)); 直接转换int 是直接截取掉小数部分,比如3.1、3.9 都直接变成3 而我单步跟踪发现可能CB里676由于浮点数计算误差,得到的其实比675.999...,这样转换后就变成675了,导致全错了 而用round进行四舍五入后结果可以正常
嗯嗯,谢谢,那为什么VS是对的呢?[/quote] 675.999 转成int得到的将是675,而不是676,产生误差的原因可能pow中计算实现方式不同,浮点数计算是有一定误差的,具体可以看pow汇编代码[/quote] 谢谢,看样子真得去学学汇编、反编译了……
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 9 楼 paschen 的回复:
这句 n += chara * pow(26, len - 1 - i); 改成 n += chara * round(pow(26, len - 1 - i));

直接转换int 是直接截取掉小数部分,比如3.1、3.9 都直接变成3
而我单步跟踪发现可能CB里676由于浮点数计算误差,得到的其实比675.999...,这样转换后就变成675了,导致全错了
而用round进行四舍五入后结果可以正常


另外你是怎么跟踪的?

我的这个却没有显示小数点和9999呢……

赵4老师 2016-01-12
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!) VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
引用 11 楼 NoMasp 的回复:
补充一下……

#include <iostream>
#include <cmath>
using namespace std;

double titleToNumber(string s) {
    double n = 0, len = s.length();
    for(int i = 0; i < s.length(); ++ i) {
        char c = s[i];
        double chara = c - 'A' + 1;
        double a = len - 1 - i;
        n += chara * pow(26.0, a);
    }
    return n;
}

int main() {
    cout<<titleToNumber("AAB");
    return 0;
}
用double的话是OK的,问题还是上一楼回答的,两个编译器内部是如何走的……
pow中的计算导致结果的误差在你转换成int时显现出来,具体可看汇编代码+单步跟踪 比较不同
paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
引用 12 楼 NoMasp 的回复:
[quote=引用 9 楼 paschen 的回复:] 这句 n += chara * pow(26, len - 1 - i); 改成 n += chara * round(pow(26, len - 1 - i)); 直接转换int 是直接截取掉小数部分,比如3.1、3.9 都直接变成3 而我单步跟踪发现可能CB里676由于浮点数计算误差,得到的其实比675.999...,这样转换后就变成675了,导致全错了 而用round进行四舍五入后结果可以正常
嗯嗯,谢谢,那为什么VS是对的呢?[/quote] 675.999 转成int得到的将是675,而不是676,产生误差的原因可能pow中计算实现方式不同,浮点数计算是有一定误差的,具体可以看pow汇编代码
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 9 楼 paschen 的回复:
这句 n += chara * pow(26, len - 1 - i); 改成 n += chara * round(pow(26, len - 1 - i)); 直接转换int 是直接截取掉小数部分,比如3.1、3.9 都直接变成3 而我单步跟踪发现可能CB里676由于浮点数计算误差,得到的其实比675.999...,这样转换后就变成675了,导致全错了 而用round进行四舍五入后结果可以正常
嗯嗯,谢谢,那为什么VS是对的呢?
nomasp 2016-01-12
  • 打赏
  • 举报
回复
补充一下……

#include <iostream>
#include <cmath>
using namespace std;

double titleToNumber(string s) {
    double n = 0, len = s.length();
    for(int i = 0; i < s.length(); ++ i) {
        char c = s[i];
        double chara = c - 'A' + 1;
        double a = len - 1 - i;
        n += chara * pow(26.0, a);
    }
    return n;
}

int main() {
    cout<<titleToNumber("AAB");
    return 0;
}
用double的话是OK的,问题还是上一楼回答的,两个编译器内部是如何走的……
flyrack 2016-01-12
  • 打赏
  • 举报
回复
才发现有这种奇怪现象 比如下面代码

#include <stdio.h>
#include <math.h>

int main() {
  int n=0,m=3;
  n=pow(26,2);
  printf("pow(26,2)=%d\n",n);
  n=pow(26.0,2.0);
  printf("pow(26.0,2)=%d\n",n);
  n=pow(26,m-1);
  printf("pow(26,int(2))=%d\n",n);
  n=pow(26.0,m-1);
  printf("pow(26.0,int(2))=%d\n",n);
	return 0;
}
在c++结果不同 是函数匹配的问题么
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 1 楼 pcboyxhy 的回复:
http://stackoverflow.com/questions/15851636/why-is-my-integer-math-with-stdpow-giving-the-wrong-answer
谢谢,你给的链接讲了浮点,我想的也是因为这个。不过我主要问题还是,同样都是pow函数,为什么两个编译器却不愿意,想知道它们内部是怎么走的……
paschen 版主 2016-01-12
  • 打赏
  • 举报
回复
这句 n += chara * pow(26, len - 1 - i); 改成 n += chara * round(pow(26, len - 1 - i)); 直接转换int 是直接截取掉小数部分,比如3.1、3.9 都直接变成3 而我单步跟踪发现可能CB里676由于浮点数计算误差,得到的其实比675.999...,这样转换后就变成675了,导致全错了 而用round进行四舍五入后结果可以正常
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 5 楼 mewiteor 的回复:
能整数运算的就不要引入浮点数,会产生精度问题。 整数乘方可以用快速幂。
对,包括自己写的用整型的求幂函数都是OK的,但是为什么同一个pow函数在两个编译器下不一样,所以我的问题是能不能教我如何剖开看内部……
mewiteor 2016-01-12
  • 打赏
  • 举报
回复
能整数运算的就不要引入浮点数,会产生精度问题。 整数乘方可以用快速幂。
fly_dragon_fly 2016-01-12
  • 打赏
  • 举报
回复
vc用的sse指令, gcc加上 -march=native -mfpmath=sse试试看
flyrack 2016-01-12
  • 打赏
  • 举报
回复

int m=3;  void A(int* x){*x=pow(26,m-1);} 
          void B(float *y){*y=pow(26,m-1); }      
            (A)                                (B)                              
            pushl     %ebp                      pushl     %ebp
            movl      %esp, %ebp                movl      %esp, %ebp
            subl      $40, %esp                 subl      $40, %esp
            movl      _m, %eax                  movl      _m, %eax
            subl      $1, %eax                  subl      $1, %eax
            movl      %eax, -20(%ebp)           movl      %eax, -16(%ebp)
            fildl     -20(%ebp)                 fildl     -16(%ebp)
            fstpl     8(%esp)                   fstpl     8(%esp)
            fldl      LC0                       fldl      LC0
            fstpl     (%esp)                    fstpl     (%esp)
            call      _pow                      call      _pow
            fnstcw    -10(%ebp)                 fstps     -12(%ebp)
            movzwl    -10(%ebp), %eax           flds      -12(%ebp)
            movb      $12, %ah                  movl      8(%ebp), %eax
            movw      %ax, -12(%ebp)            fstps     (%eax)
            fldcw     -12(%ebp)                 nop      
            fistpl    -16(%ebp)                 leave      
            fldcw     -10(%ebp)                 ret      
            movl      -16(%ebp), %edx                        
            movl      8(%ebp), %eax                        
            movl      %edx, (%eax)                        
            nop                              
            leave                              
            ret                              

看汇编代码的话 好像函数调用是一样的 就是转换的问题了
nomasp 2016-01-12
  • 打赏
  • 举报
回复
引用 23 楼 zhao4zhong1 的回复:
浮点数格式 http://bbs.csdn.net/topics/390676437
加载更多回复(5)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧