Jump to content

    
Sign in to follow this  
set bit

Не работает правильно, вычисление float в Keil

Recommended Posts

Код округление числа до десятых.

 

float x = 0;

 

x = 401 * 0.0625; //25.0625

x = x * 10; //250.625

x = x + 0.5; //251.125

x = floor(x); //251

x = x / 10; // Ошибка!

 

При делении 251 на 10, вроде должно быть 25.1, а получается 25.0999995.

Если float поменять на double, работает. Но, в маем случае очень не удобно использовать double.

Код в другой среде, работает и с float.

Понято, что происходит потеря точности.

 

Может есть другой способ округлить число до десятых.

Share this post


Link to post
Share on other sites
Понято, что происходит потеря точности.
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

 

не слушайте psL, он продемострировал незнание основ языка.

Share this post


Link to post
Share on other sites
Код округление числа до десятых.

. . . .

Может есть другой способ округлить число до десятых.

Решение через нетоместо, но решение.

Используйте sprintf c указанием точности, напр. %12.1f

ps

ну и исходник (s)printf можно посмотреть.

 

Edited by k155la3

Share this post


Link to post
Share on other sites
При делении 251 на 10, вроде должно быть 25.1, а получается 25.0999995.

Кому должно? не должно оно никому. Почитайте представление чисел в float'e, поймете- там величина всегда неточная, она просто в заданном точностью диапазоне. Кстати, по этой же причине грубой ошибкой является попытка проверить float на равенство чему-то.

У Вас просто проявилась накопленная во время вычислений (всех вычислений, а не только последнего!) ошибка.

 

Собственно Вы сами уже ответили на свой вопрос:

 

Если float поменять на double, работает.

...

Понято, что происходит потеря точности.

 

Вас смутило что "Код в другой среде, работает и с float.". Скорее всего, в этой "другой среде" (уж не Матлаб ли?) оно приводится к длинному представлению и в нем считается, вот и все.

 

Эти ошибки представления не такой очевидный факт. Я лет 15 назад пытался это же объяснить девушке (Программистка, только что окончила Московский Энергетический, очень круто было в наших краях), у нее была ошибка: если она кучу коротких данных (импульсы от счетчиков) преобразовывала в киловатт-часы, то месячная сумма этих коротких величин не сходилась с данными, показанными по барабану счетчика (конец минус начало интервала наблюдения). Причем если взять сумму импульсов за месяц и преобразовать в киловатты, то с барабаном совпадало.

Она так и не поняла про точность вычислений, у нее же писи и фокспро, они всегда точно считают. Думала что я над ней так прикалываюсь. :)

 

И не бойтесь использовать дабл, ничего страшного в нем нет.

 

Upd: вот первое попавшееся неплохое описание вопроса. Например, интересен пункт "4.2 Неассоциативность арифметических операций", но там много и другого интересного про подводные камни плавающей точки.

Share this post


Link to post
Share on other sites
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

 

не слушайте Борща с его принятым размером мантисы.

 

Keil использует IEEE-754:

http://www.keil.com/support/man/docs/armli...58938949149.htm

 

которого достаточно для представления 25.1, можно проверить, например, здесь:

https://www.h-schmidt.net/FloatConverter/

 

Share this post


Link to post
Share on other sites

Ерунда, похоже, с Keil.

 

double Round (double x){

 

return x=6.1;

 

};

 

Функция возвращает 6.099998474121, как такое может, быть.

 

 

 

https://www.h-schmidt.net/FloatConverter/, проверил

6.1 это 6.099999904632568

 

похоже, так и есть

Share this post


Link to post
Share on other sites
x = 401 * 0.0625; //25.0625

x = x * 10; //250.625

x = x + 0.5; //251.125

x = floor(x); //251

x = x / 10; // Ошибка!

А откуда числа в комментариях взялись?

Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Share this post


Link to post
Share on other sites
А откуда числа в комментариях взялись?

Это вы вручную посчитали? А теперь попробуйте вывести результат через sprintf с форматом %e

Да, вручную.

 

Уже понял, свою ошибку.

Share this post


Link to post
Share on other sites
Вы бы хоть немного ознакомились с тем, на что ссылаетесь (хотя бы по википедии):

Возможные конечные значения, которые могут быть представлены в формате, определяются основанием b, количеством цифр в мантиссе (с точностью р) и максимальным значением emax:

 

И лично вам в коллекцию: неявное приведение типов

Share this post


Link to post
Share on other sites
Вы бы хоть немного... И лично вам...

Спасибо, конечно, но Вы бы лучше мысль свою пояснили про приведение типов. Смысл моего предложения ТС был в том, что при делении на 10 происходит приведение целого к вещественному с потерей точности, а при умножении вещественных точность выше, чем при делении. В чем я не прав? Только своими словами. Не нужно "братву с википедии" подтягивать.

Share this post


Link to post
Share on other sites
В чем я не прав?
В том, что то, что вы предложили (10 ->10.0), компилятор делает сам. То есть ваше предложение эквивалентно "постучать по колесу" из известного анекдота.

Share this post


Link to post
Share on other sites
или число 25.1 невозможно представить типом float с принятым у кейла размером мантиссы. Проверьте просто x = 25.1;

число 25.1 невозмжно точно представить ни в каком варианте float, хоть double, хоть long double.

 

У Вас просто проявилась накопленная во время вычислений (всех вычислений, а не только последнего!) ошибка.

при чем тут накопленная ошибка? после выполнения floor уже все абсолютно точно.

Share this post


Link to post
Share on other sites

В двоичном формате с плавающей запятой точно представимы только целые числа, либо числа дробная часть которых есть сумма (отрицательных) степеней двойки.

 

Нужно умножать дробную часть на 2 до тех пор пока она не обнулится:

0,703125 x 2 = 1,40625 | 1

0,40625 x 2 = 0,8125 | 0

0,8125 x 2 = 1,625 | 1

0,625 x 2 = 1,25 | 1

0,25 x 2 =0,5 | 0

0,5 x 2 = 1 | 1

Т. о. 0,703125 = 0,101101(2)

 

0.1 сколько на 2 не умножай, дробная часть никогда не обнулится. Т. е. в двоичном виде точно не представимо

Edited by conan

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this