2010-11-09 5 views
3

Мне очень нравится WxWidgets, и я начал с программирования на C++. Моя программа-образец конвертирует Цельсий в Фаренгейт из текстовой формы. Вот мой основной код:WxWidgets: Простая математическая формула передает неправильные результаты?

//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, чтобы сделать его меньше, чем нужно.

EDIT: в том числе assert.h и работает lCelsius == 100 терпит неудачу в отладчике, но станд :: соиЬ lCelsius возвращает 100. Там должно быть что-то с Wx, что коверкая результат, но по-прежнему является «100». .

+1

Есть ли 'szCelsius.ToLong (& lCelsius, 10);' return 'true'? –

+0

@Vijay, я запустил assert, и он прошел, так что это 'true' – John

+0

Какой компилятор вы используете? wxWidgets использует strtol внутри, и это зависит от компилятора. –

ответ

3

Значение 1.8 (которое равно 9/5) не может быть точно представлено как двоичное число с плавающей запятой - в двоичном выражении это повторяющаяся серия цифр (1.1100110011001100110011001100 ...) - аналогично тому, как 1/3 является повторяющийся в десятичной форме.

Ближайшее представление как значение с плавающей запятой с одной точностью составляет чуть менее 1,8 - это примерно 1,7999999523). Когда это число умножается на 100, это приводит к значению чуть менее 180; и когда 32 затем добавляют, это приводит к ряду как раз под 212.

Преобразование числа с плавающей точкой в ​​целое число усекает десятичную часть, поэтому 211.999 ... становится 211.

Причина это Безразлично» t произойдет, если вы используете буква 100 в исходном коде вместо значения, предоставленного во время выполнения, потому что компилятор упростил выражение (9.f/5.f) * 100 во время компиляции до простой 180.

Если ваш компилятор поддерживает функцию C99 roundf() (объявлено в math.h), вы можете использовать его для округления до ближайшего целого числа:

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

Спасибо, это заставляет меня понять немного больше о представлениях. Раньше я знал только некоторые основные вещи. Он работает, и теперь я могу успокоиться :) – John

1

Вы можете попробовать отладить это на уровне сборки, чтобы более подробно просмотреть, что происходит.

Кроме того, как стилистическое предложение, главный термин может быть записан как (9.f/5.f), который избавляется от приведения и легче читать.

Я также спрашиваю, почему вы используете long для температуры, для меня это похоже на то, что большинство температур (особенно с участием Фаренгейта) находятся в диапазоне, поддерживаемом равным int.

+0

Не был уверен, была ли функция «ToInt», поэтому я пошел с длинными (такими же, как int на моей платформе). Я полагаю, вы имеете в виду бег -S или что-то на gcc .. это может немного усложниться, я посмотрю, что я могу собрать на сборке. – John

Смежные вопросы