我非常喜欢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 中工作得很好,当我用
lCelsius
替换 100
时,它工作得很好,即使我的调试信息清楚地表明它是 100。
您是否发现任何明显的问题,或者我只是无法做这么简单的事情?我不太确定 Wx 正在做什么来使其比应有的值少 1。
编辑:包括assert.h并在调试器中运行lCelsius == 100失败,但std::cout lCelsius返回100。Wx一定有什么问题正在破坏结果,但仍然是“100”..
值 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);
您可以尝试在程序集级别进行调试,以更详细地了解发生了什么。
此外,作为一种风格建议,主导术语可以写成
(9.f / 5.f)
,这样可以消除强制转换并且更易于阅读。
我还质疑为什么你使用
long
作为温度,对我来说,感觉好像大多数温度(特别是涉及华氏度)都在普通int
支持的范围内。