Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Странности при подсчете чисел..... Компьютер ошибается в подсчетах. 
:(
    Опции темы
Wowa
  Дата 11.2.2004, 02:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: нет
Всего: 290



Создал я значит цикл:

for ($i = 7.12; $i <= 10; $i=$i+0.01) {
...
}

При его выполнении выясняется, что компьютер прибавляет к $i 0.01 при каждом проходе цикла, но иногда компьюет прибавляет не 0.01, а меньшее число.
У меня на компьютере комп досчитал до: $i=9.51 и следуюшее значение выдало $i=9.5199999999999
Далее:
9.5299999999999
9.5399999999999
....

С чем это связано, как объясняется и как с этим бороться?
PM WWW   Вверх
Wowa
Дата 11.2.2004, 02:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: нет
Всего: 290



Запусти я этот код на другом компьютере - результат такой же.
PM WWW   Вверх
cardinal
Дата 11.2.2004, 02:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Инженер
****


Профиль
Группа: Экс. модератор
Сообщений: 6003
Регистрация: 26.3.2002
Где: Германия

Репутация: 5
Всего: 99



Компьютер не ошибается в этом случае, что подтверждает тот факт, что как ты сам сказал второй компер ведет себя точно также.
Цитата
С чем это связано?

С бинарной арифметикой.
Цитата
Как объясняется?

Объясняется тем, что бинарный система счисления не позволяет выражать дроби. Был бы я в Си, я бы сделал листинг на asm и тогда делал бы последующие выводы, т.к. не уверен чем реализована работа с дробными числами - предполагаю, что этим занимается coprocessor. Но все равно вопрос остается, что с твоим кодом делает compiler.
Цитата
Как с этим бороться?

Если это такой одиночный случай в проге, то я бы сделал так:

for (i = 712; i <= 1000; i++) {
...
}

ну и в момент надобности делал бы операцию div 100 и mod 100 получая таким образом целую часть и дробную. А если это не одиночный случай, то я бы сделал тоже самое несколько раз потому, что ничего более полезного в голову не приходит. smile.gif

p.s. Уже даже Admin нарушает правила форума! Аж три вопроса в раз: "с чем связано?", "как объясняется?" и "как с этим бороться?". biggrin.gif


--------------------
Немецкая оппозиция потребовала упростить натурализацию иммигрантов
В моем блоге: Разные истории из жизни в Германии

"Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино".  А. и Б. Стругацкие
PM   Вверх
maxim1000
Дата 11.2.2004, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



Цитата
Объясняется тем, что бинарный система счисления не позволяет выражать дроби.

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


--------------------
qqq
PM WWW   Вверх
Wowa
Дата 12.2.2004, 22:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: нет
Всего: 290



Я сделал цикл:
for ($k = 712; $k <= 1000; $k++) {
$i=$k/100;
...
}

Теперь похоже все Ок. Вычисляется все точно.
PM WWW   Вверх
val
Дата 13.2.2004, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Program developer
**


Профиль
Группа: Участник Клуба
Сообщений: 992
Регистрация: 14.1.2003
Где: г. Киев

Репутация: 1
Всего: 7



Да, эта тема обсуждалась в рубрике С/С++, действительно двоичная арифметика имеет такие ньансы при работе с действительными числами:
Цитата

одни и теже дроби в одной системе могут иметь простой вид, а в другой становиться периодическими, а периодические дроби компьютер усекает (независимо от того, как там реализована арифметика)



--------------------
Терпимость - величайшее благо человечества...
Ярчайший признак интеллекта – постоянно хорошее настроение…
PM MAIL ICQ   Вверх
OlegsDP
Дата 25.2.2004, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 25.2.2004

Репутация: нет
Всего: 1



Можно побаловаться с таким myprog.cpp:

Код

#include <stdio.h>
#include <math.h>
void main (int argc, char* argv[])
{
 if (argc != 3) {
   printf ("use: myprog val1 val2");
 } else {
   double a = atof(argv[1]), b=atof(argv[2]);
   printf (((a + b) != a) ? "AGA!" : "OGO!");
 }
}


Это сообщение отредактировал(а) OlegsDP - 25.2.2004, 14:28
PM MAIL   Вверх
Waters
Дата 29.2.2004, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 16.11.2003

Репутация: нет
Всего: нет



И в чем смысл "баловства"? smile.gif

PM MAIL   Вверх
OlegsDP
Дата 1.3.2004, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 25.2.2004

Репутация: нет
Всего: 1



Можно найти такие два числа, которые "не складываются":

myprog 1 0.000000000000001
AGA!

т.е. "сложились"


myprog 1 0.0000000000000001
OGO!

т.е. "не сложились"

PM MAIL   Вверх
PILOT
Дата 6.3.2004, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


производство
****


Профиль
Группа: Модератор
Сообщений: 2724
Регистрация: 4.4.2002
Где: москва

Репутация: нет
Всего: 54



Это связано именно с двоичной арифметикой, хотя если быть точнее то с представлением float...
число float в простом случае (я уменьшил число байт для простоты) имеет формат:
SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
где:
S - это знак
E - Экспонента (-127...+128)
M - 24бита Мантиссы (на самом деле 23)
И число представляется в виде:
±mantissa &#215; 2^exponent

Например число:
-12.5
будет представлено в виде:
0xC1480000.
Как так получилось?
Разбираемся:
формат числа: SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
в двоичном коде: 11000001 01001000 00000000 00000000
шестнадцатиричный код: 00 00 48 C1
Знак = 1 следовательно это отриц. число.
Значение Экспоненты 10000010b или 130d. Вычитаем 127 (это наше смещение нуля) из 130 получаем 3, это и есть Экспонента.
Видно, что Мантисса выражается числом:
10010000000000000000000b
считается, что перед мантиссой всегда есть единица, в этоге получаем следующее число в двоичном представлении:
1.10010000000000000000000b
Теперь учитываем экспоненту, т.к. она равна трем, то точка сдвинется на три разряда вправо:
1100.10000000000000000000b
это число и есть двоичное представление -12.5.
Проверяем (целая часть):
(1 &#215; 2^3) + (1 &#215; 2^2) + (0 &#215; 2^1) + (0 &#215; 2^0)=12 (учитвая знак: -12)
теперь дробная часть:
10000000000000000000b
(1 &#215; 2^-1) + (0 &#215; 2^-2) + (0 &#215; 2^-3) + … = 0.5
прибавляем:
-(12+0.5)=-12.5
теперь не трудно сообразить, что 0.01 представляется сложнее в мантиссе, чем -12.5, потому что 0.01 это не .0625 или .125. А для представления 0.01 придется использовать все биты мантиссы (т.е. точности не хватит), так или иначе набежит один значащий бит в мантиссе, либо в плюс либо в минус.

СУВ.


--------------------
тут могла быть Ваша реклама...
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0796 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.