Oberon space
General Category => Общий раздел => Тема начата: ilovb от Октябрь 09, 2012, 04:02:39 am
-
Всегда удивлялся виндозному калькулятору.
вычислим:
10 / 3 = 3,333333333333333
Что будет если умножить на 3 результат?
Каждый кодер знает что 9,999999999999999
Но этот засранец запоминает рациональные числа и выдает 10
К тому же он помнит не только последнее рациональное число, а на всю глубину вычислений.
Т.е. к числу 10 всегда можно вернуться выполняя обратные действия.
-
Всегда удивлялся виндозному калькулятору.
вычислим:
10 / 3 = 3,333333333333333
Что будет если умножить на 3 результат?
Каждый кодер знает что 9,999999999999999
Угу. А каждый программист знает что это не так :-) (и этим отличается программист от кодера)
$ cat float.cpp
#include <stdio.h>
int main() {
float foo;
float boo;
scanf("%f %f", &foo, &boo);
foo = foo/boo;
scanf("%f", &boo);
foo = foo*boo;
printf ("%f\n", foo);
return 0;
}
$ g++ float.cpp
$ ./a.out
10 3 3
10.000000
-
Фу ты чорт я уже и подзабыл как тип Real устроен :)
-
Н да... В Real точность только на иррациональных числах теряется (в калькуляторе аналогично)
Мне почему-то казалось что в бесконечных дробях тоже...
Давно я на нормальных языках не кодил однако :)
-
Hugs> 10/3
3.33333333333333
Hugs> 3.33333333333333*3
9.99999999999999
о_О
Однако
Hugs> let x=10/3 in 3*x
10.0
-
Н да... В Real точность только на иррациональных числах теряется (в калькуляторе аналогично)
Мне почему-то казалось что в бесконечных дробях тоже...
Давно я на нормальных языках не кодил однако :)
Ключ к пониманию механизма лежит в ответе на вопрос: "что такое бесконечные дроби для IEEE 754?"
-
Hugs> 10/3
3.33333333333333
Hugs> 3.33333333333333*3
9.99999999999999
о_О
Выкинь свой haskell.
-
Однако
Hugs> let x=10/3 in 3*x
10.0
Работать с литералами не интересно - оно их может оптимизировать на лету. Работать надо с тем, о чем компилятор не знает, то есть с вводимыми числами пользователем.
-
Hugs> 10/3
3.33333333333333
Hugs> 3.33333333333333*3
9.99999999999999
Ой, сори. Выкинуть тебе следует не haskell, а мозг: ты же потерял точность ручками скопировав текстовое обрезанное представление. 3.33333333333333 не равно тому числу что находится в памяти компьютера когда он делит 10/3.
> 3.33333333333333 == 10/3
=> False
-
Однако в виндозном калькуляторе:
1/3 + 4/3 - 5/3 = 0
а в черной каропке:
1/3 + 4/3 - 5/3 = -2.220446049250313E-160.0000000000 ???
-
Пардон, лишнее скопировал. Там так:
1/3 + 4/3 - 5/3 = -2.220446049250313E-16
Похоже что точность 10/3 - это просто неудачный пример
-
Однако в виндозном калькуляторе:
1/3 + 4/3 - 5/3 = 0
а в черной каропке:
1/3 + 4/3 - 5/3 = -2.220446049250313E-160.0000000000 ???
У виндовозного калькулятора точность выше (то есть там не 64битные числа).
-
Пардон, лишнее скопировал. Там так:
1/3 + 4/3 - 5/3 = -2.220446049250313E-16
Похоже что точность 10/3 - это просто неудачный пример
Hugs> 1/3 + 4/3 - 5/3
-2.22044604925031e-016
-
Пардон, лишнее скопировал. Там так:
1/3 + 4/3 - 5/3 = -2.220446049250313E-16
Похоже что точность 10/3 - это просто неудачный пример
Hugs> 1/3 + 4/3 - 5/3
-2.22044604925031e-016
Сколько знаков после запятой в маздайном калькуляторе? Если 15ть, то:
$ cat float.cpp
#include <stdio.h>
int main() {
double a,b,c;
scanf("%lf %lf %lf",&a,&b,&c);
a = a/3;
b = b/3;
c = c/3;
printf ("%1.15lf\n", a+b-c);
return 0;
}
$ ./a.out
1 4 5
-0.000000000000000
-
Пардон, лишнее скопировал. Там так:
1/3 + 4/3 - 5/3 = -2.220446049250313E-16
Похоже что точность 10/3 - это просто неудачный пример
Ключевой вопрос - почему это неудачный пример? ;-)
-
main = do
putStr "x: "; x<-readLn
putStr "y: "; y<-readLn
let xy=x/y
putStr "z: "; z<-readLn
putStrLn $ show x ++ "/" ++ show y ++ " = " ++ show xy
putStrLn $ show xy ++ "*" ++ show z ++ " = " ++ show (xy * z)
Main> :main
x: 10
y: 3
z: 3
10.0/3.0 = 3.33333333333333
3.33333333333333*3.0 = 10.0
-
main = do
putStr "x: "; x<-readLn
putStr "y: "; y<-readLn
let xy=x/y
putStr "z: "; z<-readLn
putStrLn $ show x ++ "/" ++ show y ++ " = " ++ show xy
putStrLn $ show xy ++ "*" ++ show z ++ " = " ++ show (xy * z)
Main> :main
x: 10
y: 3
z: 3
10.0/3.0 = 3.33333333333333
3.33333333333333*3.0 = 10.0
Именно.
-
import Data.Ratio
r = 1%3 + 4%3 - 5%3
Main> r
0 % 1
Работайте, господа, с рациональными дробями! )))
-
Н да... В Real точность только на иррациональных числах теряется (в калькуляторе аналогично)
Мне почему-то казалось что в бесконечных дробях тоже...
Про "бесконечные" дроби есть пример интересней:
printf ("%1.70lf\n", 0.3);выдает:
0.2999999999999999888977697537484345957636833190917968750000000000000000Как думаешь, почему? ;-)
А вот такое:
printf ("%1.70lf\n", 0.3f);выдает такое:
0.3000000119209289550781250000000000000000000000000000000000000000000000
Жить страшно, не правда ли?
Что выбираешь, тайд или кипячение? ;-)
-
Если бы я еще шарил в кракозябрах этих "printf ("%1.70lf\n", 0.3);" ;D
Это типа вывод числа 0.3 с большим числом знаков после запятой?
-
Если бы я еще шарил в кракозябрах этих "printf ("%1.70lf\n", 0.3);" ;D
Это типа вывод числа 0.3 с большим числом знаков после запятой?
Да. Это ("%1.70lf\n") называется - форматный вывод. И это то самое место, которое в Си сделано удобней чем в стандартной плюсовой либе. Да и во многих других языках тоже (если они не копируют это у Сей).
-
То что не все числа представимы в формате IEEE754 для меня не новость.
Смущает больше что точность не теряется при вычислении 10/3.
Я предпочитаю ожидать погрешность в этом случае. И считаю что это правильно.
виндозный калькулятор же всегда сохраняет точность на рациональных числах (по крайней мере не замечал обратного)
Соответственно я предположил что он хранит таки рациональные числа.
Но скорее всего ты прав. В нем наверно просто формат IEEE754 128 бит.
-
То что не все числа представимы в формате IEEE754 для меня не новость.
Смущает больше что точность не теряется при вычислении 10/3.
Я предпочитаю ожидать погрешность в этом случае. И считаю что это правильно.
Окэй, не хочешь подумать/повикипедить, скажу ответ: представление чисел у компьютера не десятичное, а таки двоичное. Следовательно конечные десятичные дроби могут быть бесконечными двоичными (замечу, что конечная двоичная дробь это всегда конечная же десятичная). Поэтому 0.3 - это бесконечная периодическая дробь в двоичном представлении.
А "точность" того, что выводит мелкомягкий калькулятор скорее всего связана с тем, что на экранчике мало циферек и он просто округляет (форматный вывод, ага). Ну и длинные числа. Скорее всего там даже не 128 бит, а именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). Длинные числа - это значит, что такое число легко может занимать например килобайт. В общем, ограничены лишь своп-файлом.
-
А "точность" того, что выводит мелкомягкий калькулятор скорее всего связана с тем, что на экранчике мало циферек и он просто округляет (форматный вывод, ага). Ну и длинные числа. Скорее всего там даже не 128 бит, а именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). Длинные числа - это значит, что такое число легко может занимать например килобайт. В общем, ограничены лишь своп-файлом.
Да, либо, что вероятно, там просто фиксированная точка. Эксперименты показали, что больше чем 10^10000 и меньше чем 10^-10000 оно не обрабатывает. Так что разумнее всего сделать было именно фиксированную точку.
-
Окэй, не хочешь подумать/повикипедить, скажу ответ: представление чисел у компьютера не десятичное, а таки двоичное. Следовательно конечные десятичные дроби могут быть бесконечными двоичными (замечу, что конечная двоичная дробь это всегда конечная же десятичная). Поэтому 0.3 - это бесконечная периодическая дробь в двоичном представлении.
Ну так это и означает что:
... не все числа представимы в формате IEEE754
Т.е. конечную десятичную дробь 0.3 в этом формате представить нельзя
А "точность" того, что выводит мелкомягкий калькулятор скорее всего связана с тем, что на экранчике мало циферек и он просто округляет (форматный вывод, ага). Ну и длинные числа.
Там вообще странно...
Вот результат вычисления в калькуляторе:
sqrt(2) * sqrt(2) - 2 = -1,588200079154339e-19
однако
sqrt(2) * sqrt(2) = 2
Скорее всего там даже не 128 бит, а именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). Длинные числа - это значит, что такое число легко может занимать например килобайт. В общем, ограничены лишь своп-файлом.
Ну в 1С длинные числа. И ведут они себя не так.
Собственно они себя предсказуемо ведут в противоположность IEEE754.
Погрешность всегда ровно там, где ее ожидаешь.
-
Ну так это и означает что:
... не все числа представимы в формате IEEE754
Т.е. конечную десятичную дробь 0.3 в этом формате представить нельзя
Можно, при условии что пользователь будет смотреть на нее через узкую амбразуру форматного вывода :-)
Там вообще странно...
Вот результат вычисления в калькуляторе:
sqrt(2) * sqrt(2) - 2 = -1,588200079154339e-19
однако
sqrt(2) * sqrt(2) = 2
Либо очередные выкрутасы форматного вывода (формат может зависить от целой части числа - по сравнению с двойкой остаток неточный ничтожен, а вот по сравнению с нулем - значим), либо оно таки умеет полусимвольно вычислять.
Я полагаю, что калькуляторы у разных версий винды разные. Потому как добравшись до калькулятора Win7 я увидел поведение которого раньше там не было.
-
... именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). ...
Win7 64-bit, calc.exe
1000! = 4,02387260077093773543702433923e+2567
ну и де тут длинные целые? о_О
-
... именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). ...
Win7 64-bit, calc.exe
1000! = 4,02387260077093773543702433923e+2567
ну и де тут длинные целые? о_О
Хотя, похоже, там есть длинные числа: 1000! - (1000! - 1) = 1 (делал вычисления через его память по кнопкам M+ M- MR)
-
... именно реально длинные числа (по крайней мере для целочисленнки там точно они, советую поэкспериментировать с факториалом, оценить время работы на больших числах). ...
Win7 64-bit, calc.exe
1000! = 4,02387260077093773543702433923e+2567
ну и де тут длинные целые? о_О
Дык это ж афигенно длинное целое! Или тебя предствление этого числа смучает (форматный вывод то есть)? ;-)
-
Это как раз укладывается в 128 бит формат
Число четверной точности (http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D1%87%D0%B5%D1%82%D0%B2%D0%B5%D1%80%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8)
0x 7ffe ffff ffff ffff ffff ffff ffff ffff ≈ 1.189731495357231765085759326628007 × 10^4932 (Максимальное число четверной точности)
-
Это как раз укладывается в 128 бит формат
Число четверной точности (http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D1%87%D0%B5%D1%82%D0%B2%D0%B5%D1%80%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8)
0x 7ffe ffff ffff ffff ffff ffff ffff ffff ≈ 1.189731495357231765085759326628007 × 10^4932 (Максимальное число четверной точности)
Только это целочи число ты посчитал. А пределы для плавающей точки четверной точности будут другими.
-
Вот где длинная арифметика :) http://www.wolframalpha.com/input/?i=10000000000%21
-
Это как раз укладывается в 128 бит формат
Число четверной точности (http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D1%87%D0%B5%D1%82%D0%B2%D0%B5%D1%80%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8)
0x 7ffe ffff ffff ffff ffff ffff ffff ffff ≈ 1.189731495357231765085759326628007 × 10^4932 (Максимальное число четверной точности)
ну аналогично для (10000! - 1) - 10000! = -1
при том что 10000! = 2,8462596809170545189064132121199e+35659 (calc.exe из WinXP sp3)