WxWidgets: 简单的数学公式结果错误?

3

我非常喜欢WxWidgets,并开始使用C++编程。我的示例程序将摄氏度从文本形式转换为华氏度。以下是我的基本代码:

//get "100" from textbox
wxString szCelsius = TextCtrl1->GetValue();
long lCelsius;

//attempt to cast into long
szCelsius.ToLong(&lCelsius, 10);

//formula that works in normal cases to get fahrenheit
long lFahrenheit = ((9.f/5.f) * lCelsius + 32);

//SOMEHOW this works:
//long lFahrenheit = ((9.f/5.f) * 100 + 32);

//display debug info, note it displays lCelsius as 100
wxString debuginfo;
debuginfo << _T("deg C: ")  << lCelsius << _T("\n");
//displays incorrectly as 211
debuginfo << _T("deg F: ") << lFahrenheit << _T("\n");
//this displays 100
std::cout << lCelsius;
//this fails though
assert(lCelsius == 100);

现在有了调试信息,lCelcius像预期的一样是100,但它返回的华氏温度是211而不是212!奇怪的是,在纯C中,这个公式运行得很好,当我用100替换lCelsius时,它也能正常工作,尽管我的调试信息清楚地显示它是100。
你看到任何明显的问题吗?还是我只是不能做这么简单的事情?我不确定Wx在做什么,以使它比应该少一个。
编辑:包括assert.h并在调试器中运行lCelsius == 100会失败,但std::cout lCelsius返回100。肯定有什么问题出现在Wx中导致结果混乱,但仍然是“100”..

1
szCelsius.ToLong(&lCelsius, 10); 返回 true 吗? - Vijay Mathew
@Vijay,我运行了一个断言并且它通过了,所以它是“true”。 - John
你使用哪个编译器?wxWidgets在内部使用strtol,这取决于编译器。 - Karel Petranek
@dark_charlie,GCC-4.4.3 Linux - John
使用正确的匈牙利命名法:http://www.joelonsoftware.com/articles/Wrong.html - pmg
2个回答

3

数值1.8(即9/5)无法精确表示为二进制浮点数——在二进制中,它是一系列重复的数字(1.1100110011001100110011001100……),类似于1/3在十进制中的表现。

以单精度浮点数的最接近表示为例,略小于1.8,约为1.7999999523。将该数字乘以100,结果略小于180;再加上32,则得到略小于212的数字。

将浮点数转换为整数时,小数部分将被截断,因此211.999…变成了211。

如果在源代码中使用字面量100而不是运行时提供的值,则不会发生这种情况,因为编译器在编译时将表达式(9.f/5.f) * 100简化为普通的180。

如果您的编译器支持C99中声明的roundf()函数(在math.h中声明),则可以使用它来四舍五入到最近的整数:

long lFahrenheit = roundf((9.f/5.f) * lCelsius + 32);

谢谢,这让我对表示法有了更深的理解。之前我只知道一些基础知识。现在它可以正常工作了,我可以放心了 :) - John

1

你可以尝试在汇编级别调试,以更详细地了解发生了什么。

此外,作为一些建议,前导项可以写成(9.f / 5.f),这样就不需要强制转换,并且更容易阅读。

我还质疑为什么你使用long来表示温度,对我来说,大多数温度(特别是华氏度)都在普通的int支持的范围内。


我不确定是否有“ToInt”函数,所以我选择了long(在我的平台上与int相同)。我想你是指在gcc上运行-S或其他什么东西。这可能会有点困难,我会看看我能在汇编中找到什么。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接