LINUX.ORG.RU

Отнимать от числа 2.0 - 0.1 до 0.0

 ,


0

1

начало 2.0
отнимаем 0.1 | 1.9
отнимаем 0.1 | 1.8
отнимаем 0.1 | 1.7
отнимаем 0.1 | 1.6
отнимаем 0.1 | 1.5
<-----скип------>
отнимаем 0.1 | 0.5
отнимаем 0.1 | 0.4
отнимаем 0.1 | 0.3
отнимаем 0.1 | 0.2
отнимаем 0.1 | 0.1
отнимаем 0.1 | -6.38378239159e-16
конец = -6.38378239159e-16

В условиях:
Начальное число 2.0
Отнимаем от него 0.1
Отнимать до 0.0

#!/usr/bin/python
# -*- coding: utf-8 -*-

nach = [0,2.0]
ch_1 = [0,0.1]

print 'отнимать:',ch_1[1]
if nach[0] == 0:
	while nach[1] > 0.0:
		nach[1]=nach[1]-ch_1[1]
		print 'отнимаем',ch_1[1], '|', nach[1]
print 'Конец:', nach[1]

ТЫ КТОАААА?

-6.38378239159e-16

ЧЯДНТ?



Последнее исправление: VictimOfLoveToLinux (всего исправлений: 4)

Ответ на: комментарий от VictimOfLoveToLinux

Потому что невозможно абсолютно точно представить произвольное вещественное число в таком представлении. Число -6.38378239159e-16 (~ 0, если приглядеться внимательно) — это издержки представления формата IEEE_754, и с этим ничего поделать нельзя. Хочеться точности — используй способ, который я предложил выше, либо модуль decimal

theNamelessOne ★★★★★
()

Yet another неуч, не знающий как работают числа с плавающей точкой.

Kosyak ★★★★
()
Ответ на: комментарий от VictimOfLoveToLinux

Каждое число представлено с некоторой ошибкой, и выполняя арифметические операции над такими числами, ошибка постепенно накапливается. -6.38378239159e-16 приближенно равно 0 (т.е. это очень малое по модулю число). Считай, что это ошибка, которую ты получил при вычислениях.

theNamelessOne ★★★★★
()

Всем спасибо. Няшек и чая за мой счёт этим господам.

VictimOfLoveToLinux
() автор топика
Ответ на: комментарий от VictimOfLoveToLinux
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    print 'отнимаем',ch_1[5], '|', nach[1]
ProgrammerError: unsufficient knowledge of IEEE 754 floating-point numbers
schizoid ★★★
()
Ответ на: комментарий от schizoid
python -m py_compile "t.py" (в каталоге: /tmp/bydlo_koding)
Сборка прошла успешно.

:<

VictimOfLoveToLinux
() автор топика

шото подобные темы раз-два в неделю всплывают в последнее время.

anonymous
()

Вообще очень интересно.

Даже если остановить мой пример на 0.1 потом этот 0.1 нигде нельзя использовать.

Те если попробовать сделать с ним например:

nach = [0,2.0]
ch_1 = [0,0.1]

print 'отнимать:',ch_1[1]
if nach[0] == 0:
while nach[1] > 0.1:
nach[1]=nach[1]-ch_1[1]
print 'отнимаем',ch_1[1], '|', nach[1]
print 'Конец:', nach[1]

if nach[1] == 0.1:
print 'Число равно:',nach[1]

Оно не заработает.

Хотя вообще ни каких опознавательных знаков нет, что с содержимым переменной что-то не так.

Те если бы я не довел до 0.0, я бы и не понял в чем проблема.

VictimOfLoveToLinux
() автор топика
Ответ на: комментарий от VictimOfLoveToLinux

Оно не заработает.

Ну сколько раз можно повторять! Сравнивать числа float при помощи оператора == можно разве что во всяких матлабах/октавах, где учитывается точность чисел и сравнение выполняется правильно.

А в ЯП надо писать

if(fabs(a-b) < EPS) …

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от VictimOfLoveToLinux

А нет, всё верно, это у меня ограничение в терминале на вывод строк.
Я думал оно на 99.3 залипает :з

VictimOfLoveToLinux
() автор топика
Ответ на: комментарий от VictimOfLoveToLinux

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

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

theNamelessOne ★★★★★
()
Ответ на: комментарий от VictimOfLoveToLinux

информативность в голове и руках программиста.

http://softelectro.ru/ieee754.html читать до просветления, т.к. интересных моментов с IEEE754 предостаточно, хотя в твоих программах ты вряд ли столкншься со многими.

qnikst ★★★★★
()
Ответ на: комментарий от theNamelessOne

Вообще твоя конструкция дико неудобная.
Если мне надо поменять шаг с 0.1 на 0.2 то и изначальное число придется изменить с 20 на 10.
Не говоря уж о том что в переменных у меня числа хранятся как 2.0 etc.

модуль decimal

погуглю, спасибо.

VictimOfLoveToLinux
() автор топика

Зато программирует на HTMLе.

aedeph_ ★★
()
Ответ на: комментарий от Eddy_Em

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

float'ы нигде нельзя.

aedeph_ ★★
()
Ответ на: комментарий от aedeph_
octave:23> a = single(102.5/1025)
a =  0.10000
octave:24> b = 0.1
b =  0.10000
octave:25> printf("a=%.16f, b=%.16f\n", a, b)
a=0.1000000014901161, b=0.1000000000000000
octave:26> a == b
ans =  1
Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Такое поведение является непредсказуемым. Использовать его - отстреливание себе ноги, причём изощренное.

aedeph_ ★★
()
Ответ на: комментарий от Eddy_Em

bc и не использует плавающей точки по определению
(если считать спецификации POSIX определением).
man 1p bc

ABW ★★★★★
()
Ответ на: комментарий от aedeph_

Мы про float'ы вообще-то говорим:

octave:47> single(e^log(10)) == 10.0
ans =  1
Понятно, что у double eps намного меньше (и, похоже, вообще не учитывается октавой).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от aedeph_

ты понимаешь, что такое eps?

«квант» числа с плавающей точкой. Для float и double он, естественно, разный. Просто иногда его еще и немного увеличивают «для надежности».

Есть FLT_EPSILON и есть DBL_EPSILON, команда eps в Octave отображает DBL_EPSILON (но сравнение float'ов там явно идет через FLT_EPSILON).

Кстати, в octave можно и float-eps узнать

octave:50> eps('single')
ans =  1.1921e-07

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от aedeph_

P.S.

То есть ты утверждаешь, что double не является float'ом?

???

Что значит «double не является float'ом»? sizeof(float) == 4, sizeof(double) == 8. И как бы из названия следует, что double - число двойной точности.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от VictimOfLoveToLinux

А мне как-то раз для одного итеративного алгоритма не хватило точности double…

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от VictimOfLoveToLinux

Тут вопрос не в точности подсчётов. А в самом принципе. Числа с плавающей точкой всегда представляются с погрешностью, независимо от того, на компьютере они вычисляются или вручную. Сравнивать в лоб цифры за пределами погрешности нельзя. Если человек при сравнении знает, до какой точности ему нужно сравнивать, то популярные реализации плавучки (когда хранится только значение, без погрешности) сравнивать побитово числа не позволяют принципиально. Раньше это были одни из первых вещей, которым учили при начале работы с плавающей точкой. Хоть на Бейсике, хоть на программируемых калькуляторах.

Собственно, пример с некорректным обратным отсчётом при вычитании был обязательным примером при рассмотрении оператора FOR .. TO .. STEP .. NEXT :)

KRoN73 ★★★★★
()
Ответ на: комментарий от Eddy_Em

И как бы из названия следует, что double - число двойной точности.

А single - число одинарной. При этом по-умолчанию используется двойной. Вот такой вот парадокс разрабов октавы.

aedeph_ ★★
()
Ответ на: комментарий от aedeph_

И из-за этого «парадокса» приходится каждый раз явно указывать, что число - одинарной точности. Иначе оперативка очень быстро кончается…

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от VictimOfLoveToLinux

Тут не погрешность. У тебя просто возникают числа с периодом. В десятичной системе счисления периодов может и не быть, но компьютер переводит числа в двоичную систему счисления, а при таком переходе всегда может возникнуть период. Понятное дело, что-то отсекается при этом. Погрешность же - следствие, а не причина.

Вообще-то, мы изучали это еще в школе. В советской школе, когда еще нужны были толковые инженеры на [преимущественно военных] заводах.

dave ★★★★★
()
Ответ на: комментарий от dave

В советской школе, когда еще нужны были толковые инженеры на [преимущественно военных] заводах.

Я уже в россиянской(sic!) учился :з информатика у нас была в виде листа бумаги и карандаша. Преимущественно рассказывали как открывать офисные программы и использовать мышь. Ну и что в 8 битов в 1 байте и 1024 мегабайтов в 1 гигабайте.
Даже бейсиком не научили пользоваться :< компьютеров просто не было. Украли наверно.

А математику я осилил только в 8 классе. И когда осилил меня обвинили в списывании и я опять забил. Лол.

VictimOfLoveToLinux
() автор топика
Ответ на: комментарий от VictimOfLoveToLinux

Ну что за унылые вбросы, я же учусь только.

Вот как раз учиться надо с представление данных в ОЗУ, а потом уже программки писать :)

xorik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.