float
От: Serii  
Дата: 21.09.04 21:40
Оценка:
Hello

Возник следующий вопрос:

char a[]="222.91";
float f=atof(a);

f=222.91

А если:
char a[]="2222.91";
float f=atof(a);

то f=2222.9099999..

Хочется разобраться, почему так и как с этим бороться.
Посоветуйте, плз, литературу по данной теме.
Спасибо
Re: float
От: Слава Шевцов Россия http://www.rentaguru.ru/
Дата: 21.09.04 21:58
Оценка:
Здравствуйте, Serii, Вы писали:

S>
S>char a[]="222.91";
S>float f=atof(a);
S>

S>f=222.91

S>А если:

S>
S>char a[]="2222.91";
S>float f=atof(a);
S>

S>то f=2222.9099999..

S>Хочется разобраться, почему так и как с этим бороться.


С этим можно бороться лишь округлением в 7-8 знаке. Дело в том, что машина преобразует данные с некоторой ограниченной точностью. Отсюда и такие накладки.

S>Посоветуйте, плз, литературу по данной теме.


----------------------------------------------------------------------------------------------
Rentaguru
Re[2]: float
От: Lutien Россия  
Дата: 21.09.04 22:09
Оценка:
СШ>С этим можно бороться лишь округлением в 7-8 знаке. Дело в том, что машина преобразует данные с некоторой ограниченной точностью. Отсюда и такие накладки.

Ну почемуже, никто не мешает сделать свой тип, с целочисленной переменной например типа __int64 под мантиссу, и никаких траблов не будет.
... << RSDN@Home 1.1.3 stable >>
Re[2]: float
От: Lutien Россия  
Дата: 21.09.04 22:09
Оценка:
СШ>С этим можно бороться лишь округлением в 7-8 знаке. Дело в том, что машина преобразует данные с некоторой ограниченной точностью. Отсюда и такие накладки.

Ну почемуже, никто не мешает сделать свой тип, с целочисленной переменной например типа __int64 под мантиссу, и никаких траблов не будет.
... << RSDN@Home 1.1.3 stable >>
Re: float
От: LaptevVV Россия  
Дата: 22.09.04 06:35
Оценка:
Здравствуйте, Serii, Вы писали:

S>Хочется разобраться, почему так и как с этим бороться.

S>Посоветуйте, плз, литературу по данной теме.
Найди старую книжку МакКракен, Дорн. Численные метода и программирование на фортране.
Разжевано — по самое не хочу.
Кратко — потому что 0.1 в двоичной системе представляетсобой периодическую дробь, то есть ТОЧНО не переводится (из-за множителя 5).
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: float
От: Слава Шевцов Россия http://www.rentaguru.ru/
Дата: 22.09.04 07:10
Оценка:
Здравствуйте, Lutien, Вы писали:

СШ>>С этим можно бороться лишь округлением в 7-8 знаке. Дело в том, что машина преобразует данные с некоторой ограниченной точностью. Отсюда и такие накладки.


L>Ну почемуже, никто не мешает сделать свой тип, с целочисленной переменной например типа __int64 под мантиссу, и никаких траблов не будет.


Будет, будет. Когда у числа стоит 9 в периоде и последний знак не округляется а обрезается, то количество девяток после запятой значения не имеет.
----------------------------------------------------------------------------------------------
Rentaguru
Re[4]: float
От: Lutien Россия  
Дата: 22.09.04 07:56
Оценка:
Здравствуйте, Слава Шевцов, Вы писали:


СШ>Будет, будет. Когда у числа стоит 9 в периоде и последний знак не округляется а обрезается, то количество девяток после запятой значения не имеет.


Наскоьлко я поняла, изначальна проблема была в том, что число 2222.91 в float из строки переводится как 2222.9099999 а это как раз происходит из-за особенностей представления чисел в типах данных с плавающей точкой.
если же сделать свой типа на базе целочисленного типа, таких траблов не будет, но работать будет естественно медленнее.
... << RSDN@Home 1.1.3 stable >>
Re[5]: float
От: Слава Шевцов Россия http://www.rentaguru.ru/
Дата: 22.09.04 08:05
Оценка: -1
Здравствуйте, Lutien, Вы писали:

СШ>>Будет, будет. Когда у числа стоит 9 в периоде и последний знак не округляется а обрезается, то количество девяток после запятой значения не имеет.


L>Наскоьлко я поняла, изначальна проблема была в том, что число 2222.91 в float из строки переводится как 2222.9099999 а это как раз происходит из-за особенностей представления чисел в типах данных с плавающей точкой.

L>если же сделать свой типа на базе целочисленного типа, таких траблов не будет, но работать будет естественно медленнее.

Лютьен, эта проблема так просто не решается. Если LaptevVV прав с тем, что корни уходят аж в двоичное представление 0.1, то эта проблема принципиально неразрешима иначе, чем округлением на одном из этапов.

P.S. Самое смешное, что оба результата (2222.91 и 2222.90(9)) в математике эквивалентны. 2222.91 тождественно равно 2222.90(9)
----------------------------------------------------------------------------------------------
Rentaguru
Re[6]: float
От: LaptevVV Россия  
Дата: 22.09.04 08:12
Оценка:
Здравствуйте, Слава Шевцов, Вы писали:

L>>Наскоьлко я поняла, изначальна проблема была в том, что число 2222.91 в float из строки переводится как 2222.9099999 а это как раз происходит из-за особенностей представления чисел в типах данных с плавающей точкой.

L>>если же сделать свой типа на базе целочисленного типа, таких траблов не будет, но работать будет естественно медленнее.

СШ>Лютьен, эта проблема так просто не решается. Если LaptevVV прав с тем, что корни уходят аж в двоичное представление 0.1, то эта проблема принципиально неразрешима иначе, чем округлением на одном из этапов.

Что значит "если прав"? Переведите 0.1 в двоичную систему
0|1
---
0|2
0|4
0|8
1|6
1|2
0|4
0|8
1|6
1|2
Итого, имеем в двоичной системе 0.0(0011)
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: float
От: glyph  
Дата: 22.09.04 08:14
Оценка: 1 (1)
Здравствуйте, Lutien, Вы писали:

СШ>>Будет, будет. Когда у числа стоит 9 в периоде и последний знак не округляется а обрезается, то количество девяток после запятой значения не имеет.

Как я понял, как раз имеет. В случае
L>Наскоьлко я поняла, изначальна проблема была в том, что число 2222.91 в float из строки переводится как 2222.9099999 а это как раз происходит из-за особенностей представления чисел в типах данных с плавающей точкой.
L>если же сделать свой типа на базе целочисленного типа, таких траблов не будет, но работать будет естественно медленнее.
Не факт. По старой памяти, алгоритм Брезенхейма оптимизирован путем перехода к целочисленной арифметике.
Вообще охотно пофилософствую на эту тему, но в другом форуме.
Что касается сабжа, то посоветую посмотреть в сторону float.h и здесь. В заголовочном файле есть макросы, которые влияют на это "поведение".
Re[6]: float
От: glyph  
Дата: 22.09.04 08:23
Оценка:
Здравствуйте, Слава Шевцов, Вы писали:

СШ>P.S. Самое смешное, что оба результата (2222.91 и 2222.90(9)) в математике эквивалентны. 2222.91 тождественно равно 2222.90(9)

Расскажите это инженеру.
В инженерных расчетах устанавливается точность. В учебных целях обычно до 4го знака после запятой. Получам два числа — 2222.9100 и 2222.9099. Непорядок.
Видимо, какие-то грабли в самой atoi(), т.к. если переводить руками и заносить в FPU, то получается нормально...
Re[7]: float
От: glyph  
Дата: 22.09.04 08:23
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Что значит "если прав"? Переведите 0.1 в двоичную систему

А Вы для начала запишите, в каком виде 0.1 будет представлено в машинном виде, а только потом переводите в двоичный вид. Результат другой будет.
Re[8]: float
От: LaptevVV Россия  
Дата: 22.09.04 08:27
Оценка:
Здравствуйте, glyph, Вы писали:

G>Здравствуйте, LaptevVV, Вы писали:


LVV>>Что значит "если прав"? Переведите 0.1 в двоичную систему

G> А Вы для начала запишите, в каком виде 0.1 будет представлено в машинном виде, а только потом переводите в двоичный вид. Результат другой будет.
Машинный вид мантиссы определяется стандартом IEEE — это еще усложняет проблему (в частности, скрытая единица). Я же здесь просто продемонстрировал, что при переводе 0.1 в двоичную систему получается период — значит в машине приходится хвостик обрезать. Стратегия "обрезания" тоже может быть разной (см. описание препроцессора Intel): с отсечением или округлением, например.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[9]: float
От: glyph  
Дата: 22.09.04 08:53
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, glyph, Вы писали:


G>>Здравствуйте, LaptevVV, Вы писали:


LVV>>>Что значит "если прав"? Переведите 0.1 в двоичную систему

G>> А Вы для начала запишите, в каком виде 0.1 будет представлено в машинном виде, а только потом переводите в двоичный вид. Результат другой будет.
LVV>Машинный вид мантиссы определяется стандартом IEEE — это еще усложняет проблему (в частности, скрытая единица). Я же здесь просто продемонстрировал, что при переводе 0.1 в двоичную систему получается период — значит в машине приходится хвостик обрезать. Стратегия "обрезания" тоже может быть разной (см. описание препроцессора Intel): с отсечением или округлением, например.
Верно. Это я спутал с инженерным представлением числа. Оно бы тогда записалось как 1.0 * 10 в -1. А у нас основание мантиссы — 2. Каюсь.
По ходу треда. Автор! Ты вообще читал варнинги, которые тебе выдает компилятор?
Там, английским по белому написано: warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data. Так что объявляй переменные как double.
Суть происходящего можно узнать из Книги Зубкова.
Re: float
От: zmaks100 Канада  
Дата: 22.09.04 11:22
Оценка:
Здравствуйте, Serii, Вы писали:

S>Hello


S>Возник следующий вопрос:


S>
S>char a[]="222.91";
S>float f=atof(a);
S>

S>f=222.91

S>А если:

S>
S>char a[]="2222.91";
S>float f=atof(a);
S>

S>то f=2222.9099999..

S>Хочется разобраться, почему так и как с этим бороться.

S>Посоветуйте, плз, литературу по данной теме.
S>Спасибо

http://docs.sun.com/source/806-3568/ncg_goldberg.html

С уважением,
zmaks100
Re[10]: float
От: Serii  
Дата: 22.09.04 18:03
Оценка:
Здравствуйте, glyph, Вы писали:


G> По ходу треда. Автор! Ты вообще читал варнинги, которые тебе выдает компилятор?

G> Там, английским по белому написано: warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data. Так что объявляй переменные как double.
с double такая же история

bye
... << RSDN@Home 1.1.3 stable >>
Re[11]: float
От: glyph  
Дата: 23.09.04 11:59
Оценка:
Здравствуйте, Serii, Вы писали:

S>Здравствуйте, glyph, Вы писали:



G>> По ходу треда. Автор! Ты вообще читал варнинги, которые тебе выдает компилятор?

G>> Там, английским по белому написано: warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data. Так что объявляй переменные как double.
S>с double такая же история
int _tmain(int argc, _TCHAR* argv[])
{
    char a[] = "222.91";
    char b[] = "2222.91";
    double af = atof(a);
    double bf = atof(b);
    printf( "Here we go: \n\
            af = %f\n\
            bf = %f\n", af,bf);
    return 0;
}

Вывод:
Here we go:
     af = 222.910000
     bf = 2222.910000
Press any key to continue

Visual Studio .NET, все настройки по умолчанию. Измени объявления af и bf и увидишь warnings.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.