Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение Kavka »

Написал в продолжение этого сообщения, но, IMHO, тема больше подходит для "Разных вопросов по МК", т.к. относится не только к AVR и AVR Studio. Поэтому перенёс сюда.

Я бы сказал, что ошибки в программах связанные с особенностями чисел в формате плавающей точки это не просто "грабли", а "подводные грабли". По аналогии с "подводными камнями"... :))
Не всем же преподают вычислительную математику. Да и не все её учат, даже если им преподают. :)
Хотя, IMHO, достаточно знать несколько свойств/характеристик представления чисел с плавающей точкой и логично мыслить, чтобы избегать ошибок.

Есть несколько примеров (чуть позже попробую найти откуда я это взял).
Результаты удивят, конечно же, не всех, но, думаю, что многих!
Те кого результаты не удивят и так, думается, знают почему оно так получается.
А вот остальным надо бы задуматься, что у них есть пробел :) в познаниях.
И не смотрите, что в примерах используется тип float (одинарная точность), для double тоже можно придумать.

Только что проверил эти примеры на
gcc version 4.7.2 20130108 [gcc-4_7-branch revision 195012] (SUSE Linux)
Спойлер

Код: Выделить всё

#include "stdio.h"
int
main(int argc, char *argv[])
{    
    float a, b, f;
    a=123456789;
    b=123456788;     
    f=a-b;	
    printf("Result: %f\n", f);
    return 0;
}
Думаете, что результат будет 1. Ну-ну.

Код: Выделить всё

#include "stdio.h"
int
main(int argc, char *argv[])
{
    float a;
    double b, f;
    a=123456789.123457;
    b=123456789.123457;
    f=a-b;
    printf("Result: %f\n", f);
    return 0;
}
Должен быть ноль? Должен, но не обязан.

Код: Выделить всё

#include "stdio.h"
int
main(int argc, char *argv[])
{
    float a, b, c, d;
    a = 1.0;
    b = 3.0;
    c = a / b;
    d = (c - 1.0/3.0) * 1e9;
    printf("Result: %f\n", d);
    return 0;
}
Тоже ноль? Неа!

Код: Выделить всё

#include "stdio.h"
int
main(int argc, char *argv[])
{
    float a, b;
    long n;
    a = 300;
    b = 0.00001;
    for (n=30000000; n>0; n--) {
        a=a-b;
    }
    printf("Result: %f\n", a);
    return 0;
}
Думаете опять ноль?
Дописал на следующий день:
Вот (или так) откуда примеры.
Там и подробности представления чисел с плавающей точкой по стандарту IEEE 754 и описание возможных проблем.
И всё это с картинками и на русском. :)
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение YS »

Ну так ничего удивительного. :)

Главное, что из этих соображений в частности следует, что никогда нельзя проверять вещественные числа на точное равенство/неравенство; смысл имеет только проверка на попадание в некий диапазон.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Реклама
Аватара пользователя
blackx
Говорящий с текстолитом
Сообщения: 1518
Зарегистрирован: Пт дек 28, 2012 21:56:46
Откуда: St. Petersburg

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение blackx »

О, еще где-то был пример, если я правильно помню, где к большому float прибавляли 1, а значение не изменялось :music:
Что приводило к зависанию программы в цикле :P
Многие проблемы, в принципе, решаются заменой float на double. Тогда погрешности для большинства задач будут приемлемыми.

PS. Вот сейчас немного подумал на эту тему.. а почему так происходит? В первом же примере, например. Разве числа при выполнении операции вычитания не представляются в памяти как double? (слышал на intel-ах для этого даже 80-битный формат используется).

Почему если числа явно объявить как double, все ок, а если оставить float, получается погрешность?
Изображение only pure true norwegian blackx Изображение
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение Kavka »

blackx писал(а):PS. Вот сейчас немного подумал на эту тему.. а почему так происходит? В первом же примере, например. Разве числа при выполнении операции вычитания не представляются в памяти как double? (слышал на intel-ах для этого даже 80-битный формат используется).
Это зависит от компилятора. Во времена турбо си/паскаля версий 5 или 6 возможно оно так и было, когда был только один FPU для расчётов (который, если мне не изменяет память, мог так и делать). А сейчас есть MMX/SSE, NEON и т.п., которые работают в пределах заданного формата чисел и строго в пределах стандарта.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
blackx
Говорящий с текстолитом
Сообщения: 1518
Зарегистрирован: Пт дек 28, 2012 21:56:46
Откуда: St. Petersburg

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение blackx »

Понятно, спасибо :)
Изображение only pure true norwegian blackx Изображение
Реклама
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6312
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение Jack_A »

Kavka писал(а): А сейчас есть MMX/SSE, NEON и т.п., которые работают в пределах заданного формата чисел и строго в пределах стандарта.
Но мы в разделе "Микроконтроллеры", и здешние компиляторы понятия не имеют об MMX и пр., а только об своих AVR,PIC etc и, не рассчитывая на железное FPU, делают плавучку программно.
Начинал свою работу с МК на Томсоновских ( нонче STM ) камнях ST62XX. так что там не только FPU не было -- даже сдвига вправо ! Не говоря уже про Си. Так что пришлось всю плавучку, включая функции, лепить с нуля. До сих пор вспоминаю с удивлением : оно работало !
Реклама
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Числа с плавающей точкой по стандарту IEEE 754. Ошибки.

Сообщение Kavka »

Вообще-то вопрос был о расширении точности промежуточных результатов у интеловского FPU (x87 сопроцессор), которой нет на других архитектурах (AFAIK)
А вы думаете эмуляция как делается?
Kavka писал(а):... пределах заданного формата чисел и строго в пределах стандарта.
Может не строго по стандарту, особенно в МК где ресурсов мало. Но, думается мне, что там где ресурсов мало, дабы их сэкономить могут отступать от стандарта. А отступы от стандарта могут приводить ещё к большим "глюкам". И если уж по стандарту, не зная особенностей, можно получить "косяки", то что уж говорить о не полном соблюдении стандарта.
Собственный вариант реализации это здорово! Как минимум, надо не слабо разобраться сначала! 8)
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Ответить

Вернуться в «Разные вопросы по МК»