[c++] преобразовать строку в double

neorus

Столкнулся с проблемой при работе над адаптером: не могу корректно преобразовать строку в double.
Например, значение “000093.0100” превращается в 93.099999999999994 всеми тремя способами, найденными мной:


inline double convertToDouble(const std::string& s)

{



//первый способ

double n = atof ( s.c_str );



//второй способ

char * y;

double z = strtod ( s.c_str &y );



//третий способ

std::istringstream i(s);

double x;

if (!(i >> x

return 0;

//throw BadConversionException("convertToFloat(\"" + s + "\")");



return x;

}

serega1604

“000093.0100” превращается в 93.099999999999994
есть уверенность, что этой точности не хватит?

apl13

Выводи результат с точностью четыре знака после, будет тебе 0100.

IG_rok777

Я пользовался функцией FloatToStr она выдавала подобные результаты, когда я присваивал значение переменной с типом float, заменил на double, все заработало.

Sanjaz

А ты вычти 000093.0100 и то число, которое получится после преобразования и посмотри в каком знаке у тебя будет не ноль. Мне кажется, что это будет где-то 300-ый знак после запятой.
А вообще, это не твоя проблема и не проблема алгоритма. Это проблема представления чисел в компе. Почитай стандарт IEEE-754

VitMix

Вроде очевидно, что в 15-ом знаке после запятой не ноль будет.

VitMix

Тип double представляет числа как m*2^n, где m и n --- целые числа. Диапазоны возможных значений m и n ограничены количеством отведённых под них разрядов. Далеко не каждое действительное число может быть представлено в таком виде с абсолютной точностью.
Если тебе надо уметь представлять любое действительно число, то это невозможно в условиях ограниченной памяти. Если надо уметь представлять любое рациональное число, то используй представление m/n. Если надо уметь представлять любую конечную десятичную дробь, то используй m*10^n.

klyv

Вроде очевидно, что в 15-ом знаке после запятой не ноль будет.
А вот и нет. С плавающей арифметикой ничего нельзя точно знать заранее.

barbos

А стандарт зачем придумали?

klyv

чтобы всё было одинаково неточно ;)

SPARTAK3959

Стандарт на операции FPU есть только в java и то он по умолчанию не включен вроде бы.

barbos

Может быть я что-то неправильно понимаю, но что такое упомянутый выше
IEEE 754, которому следуют производители CPU и FPU?
К тому же тут заявляется, что Java следует именно этому стандарту.

psihodog

А ты вычти 000093.0100 и то число, которое получится после преобразования и посмотри в каком знаке у тебя будет не ноль.
>>> 000093.0100 - 93.099999999999994
-0.0899999999999892
фигасе, ну и точность....

conv3rsje

фигасе, ну и точность....
В постановке опечатка :)
In [1]: float('93.01')
Out[1]: 93.010000000000005

In [2]: float('93.1')
Out[2]: 93.099999999999994

А так точность 6 * 10 ^ -15 (тобишь 0.000000000000006)

SPARTAK3959

Это стандарт на CPU и FPU, а не на то, что у тебя будет, если ты напишешь в каком-нибудь языке a+b - компиляторы могут реализовывать это по-разному (особенно если идет работа не с 80-битными числами).

barbos

Число хранится в памяти. То, как оно хранится - задается стандартом.
Числа складываются на процессоре, способ сложения задается стандартом.
Чем по-твоему занимается компилятор?

procenkotanya

В модели x87 по умолчанию все вычисления производятся с 80-битной точностью, что приводит к проблемам "слишком точных вычислений". Это один из самых старых и известных "не-багов" GCC: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323

barbos

А этими сопроцессорами еще не прекратили пользоваться?

procenkotanya

Эта модель вычислений используется на всех x86 процессорах (в 32-битном режиме). Такое вот тяжёлое наследие, перенятое интелом у моторолы.

barbos

Ok, видимо я не совсем прав )
Кстати, что делает gcc, когда встречает, скажем, перемножение двух float-чисел?
Мне так показалось, что майкрософтовский компилятор старается производить
эти вычисления при помощи SSE, если такие ему доступны.

conv3rsje

что делает gcc
То, что ему скажут (см -mfpmath и -msse*)

barbos

Спасибо )
Оставить комментарий
Имя или ник:
Комментарий: