Максимальное число

Marina11

Такой вопрос возник..есть ну так сказать " машинный ноль" только в обратную сторону, т.е. максимальное число, котор машина может считать (ответ : для double 1.7e-308...1.7e+308 не рассматривается)? Просто возникла такая проблема, что машина читает из файла число с 30ю знаками, но из них только первые 15 верны, а дальше какие-то др числа ставит.. типа не получается у неё такое большое число прочитать...

artimon

Вопрос не про максимальное число, а про точность.
В твоём случае ты ответил на свой вопрос. 15 знаков.

durka82

Читай как строку и/или использую библиотеки, которые позволяют работать с числами с произвольной точностью.

Marina11

а это как ещё? какие есть библиотеки для этого?

sergei1969

всякие
а на чём пишешь-то?

Marina11

С++ (visual)

yolki

У long double - 21 знак верный

yolki

Смысл в том, что вещественные числа расположены дискретно (ибо компьютеры конечны).
с разной плотностью - около нуля погуще, около единицы - пореже, около тысячи - ещё больше расстояния между соседними числами.
мышинным эпсилон называется расстояние между соседними числами около единицы.
для double это примерно 1e-16, для long double 1e-21, для float 1e-6
чтобы выяснить расстояние между числами около некоторого числа X, надо эпсилон умножить на это самое X.
т.е. около миллиона для float расстояние равно X*float_eps=1e6*1e-6=1. (примерно)
т.е. с точки зрения машины 1'000'000.0 и 1'000'000.5 неразличимы (для типа float)
расстояние между числами около нуля - 1e-308 (double)
И машина вполне себе нормально считает числа порядка 1e200 - складывает, умножает. тут только надо себе отчёт отдавать в том, сколько знаков мы имеем.

shlyumper

Используй GMP если тебе нужна большая точность.

Marina11

Это просто Макаров-Землянский прикалывается, просит чтобы ему в виде %30.30f выводило, а машина по этому поводу ерунду выдает....и никак не сдать ему задачку..

artimon

Может он просто ждёт от тебя того ответа, который написал ?
Что б ты ему объяснил, что так не бывает.

Marina11

на самом деле так и есть (т.е. он всегда выпендривается в хорошем смысле..перед студентами первого курса типа вы этого не знаете, а я вот знаю.. тока я пока не совсем уверена, что именно такой ответ...(сорри)
до пятница все равно разберусь (придется) =)
Даже был такой случай: я сидела в 13-08 а он у кого-то прогу принимал со словами "а ща я покажу, как нужно делать, чтобы прога зависла и не работала..гыгы"...

artimon

Сорри. Ошибся с полом

Marina11

тока что написала прогу (две строчки) чтобы считало машинный ноль..
eps=1.110223e-16 и для double, float, long double. почему так?

Ivan8209

Прогу в студию.
"Ай-яй-яй" другое говорит.
---
...Я работаю антинаучным аферистом...

Marina11

#include <stdio.h>
#include <math.h>
double eps;
void main
{
eps=1.;
while 1.+eps)>1)
{
eps/=2;
}
printf("eps=%.10le\n",eps);
}
вот оно

yolki

Неправильно! надо так:


#include <stdio.h>
#include <math.h>
typedef float mytype;
mytype eps,one,tmp;
void main
{
eps=1.;
one=1.;
tmp=one+eps;
while (tmp>one)
{
eps/=2;
tmp=one+eps;
}
printf("eps=%g\n",eps);
}


long double на MSVS 7.0 почему-то кажет тот же результат, что и дабл.
на gcc всё пучком

Ivan8209

Ты бы хоть пояснил, какого типа значение "1.".
Опять же, это не очень-то нуль.
Или подразумевалась именно наименьшая достижимая относительная
погрешность?
---
...Я работаю антинаучным аферистом...

shlyumper

Вообще-то все ораторы немного заблуждаются. Нас когда-то учили, что эта самая максимальная точность еще зависит от того, какие операции над числами выполнять.
Простой пример:


#include <math.h>
int main
{
int i=0;
double a=0;
double eps=1, eps1;
while(a != (double)1.0) {
eps /= (double)2.0;
a += eps;
i++;
}
printf("eps+ = %le, i=%d\n", eps, i);
i=0;
a=(double)1.0;
eps = 1;
while(a != (double)0.0 && eps != (double)0.0) {
eps1 = eps;
eps /= (double)2.0;
a -= eps;
i++;
}
printf("eps- = %le, i=%d\n", eps1, i);
return 0;
}


для gcc, double получаем
eps+ = 5.551115e-17, i=54
eps- = 4.940656e-324, i=1075

Ivan8209

Мне безразлично сколько --- я могу узнать, что говорит
"Ай-яй-яй," но ты неправ.
---
...Я работаю антинаучным аферистом...

shlyumper

но ты неправ.

В чем именно я не прав? Ты действительно считаешь, что компьютерная точность вычислений не зависит от постановки вычислений?

yolki

И чем же я не прав?
у меня gcc на три типа выдаёт разные результаты - порядка 1e-8, 1e-16, 1e-22
постановка задачи была - посчитать (оценить порядок) расстояние между числами в окрестности единицы.
я считаю, приведённая программа с этой задачей справилась.

Ivan8209

В том, что наименьшая достижимая погрешность зависит от
способа вычислений.
---
...Я работаю антинаучным аферистом...

lenabarskaya

long double на MSVS 7.0 почему-то кажет тот же результат, что и дабл.

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

yolki

скомпилял два файла - с даблом и лонг даблом.
fc: no differences encountered

Marina11

я очень сомневаюсь, что машинная точность зависит от типа.....я ведь не ищу точность типа, а ищу точность машины...
...а что касается подключить библиотеку, то как я это сделаю в комп классе? и я про то..
в любом случае, всем спасибо..

lenabarskaya

Маза у MS long double 8-байтовый

shlyumper

В абстрактных языках программирования на абстрактных компьютерах, она, конечно же не зависит от постановки вычислений.
Но если перейти к конкретной прикладной задаче - вычисления на C на x86, то точность результата от постановки вычислений зависит. Существует достаточно классический пример (программу для иллюстрации лень писать):
Будем вычислять значение функции разложением в ряд. Возьмем достаточное количество членов ряда, чтобы наверняка превысить компьютерную точность, и посчитаем две суммы: одну начиная суммирование с больших членов ряда к меньшим, а вторую - наоборот, от меньших членов к большим. Результаты будут различаться.

shlyumper

И чем же я не прав?
постановка задачи была - посчитать (оценить порядок) расстояние между числами в окрестности единицы.
я считаю, приведённая программа с этой задачей справилась.

приведенный мной пример тоже считает точность в окрестностях единицы. Только первая точность получается в окрестностях единицы, если к ней приближаться со стороны 0, а вторая - если приближаться со стороны +oo. Результаты различаются. Зависят от постановки вычислений.

mysha

Прости дядя, но ты описался... ну или лапши у тебя излишек
первый цикл действительно считает что-то в районе 1
но второй то в районе нуля...
Поэтому такая разительная разница... .940656e-324
324-16=308 точность предсказанная базилио

Marina11

определение машинного нуля: минимально возможное eps, для котор верно eps+1>1
вот нафлудили-то, я ещё больше запуталась....

shlyumper

Ладно тебе придираться к мелочам. Просто что под руками было, то и заслал copy-paste'ом.
Держи правильный подсчет при приближении от 0 и приближении от 2. Результаты получишь разные, конечно не 1e-324 как у 0, но один порядок разницы все равно есть:


#include <math.h>
int main
{
int i=0;
double a=0;
double eps=1, eps1;
while(a != (double)1.0) {
eps /= (double)2.0;
a += eps;
i++;
}
printf("eps+ = %le, i=%d\n", eps, i);
i=0;
a=(double)2.0;
eps = 1;
while(a != (double)1.0 && eps != (double)0.0) {
eps1 = eps;
eps /= (double)2.0;
a -= eps;
i++;
}
printf("eps- = %le, i=%d\n", eps1, i);
return 0;
}


eps+ = 5.551115e-017, i=54
eps- = 2.220446e-016, i=53

shlyumper

определение машинного нуля: минимально возможное eps, для котор верно eps+1>1

Корявое определение. Чем хуже минимальное eps', для которого верно 1-eps' < 1?
Для справки, eps != eps'.

bleyman

eps+1>1
С чего бы это вдруг...
Console.WriteLine(float.Epsilon.ToString + " " + double.Epsilon.ToString;
1.401298E-45 4.94065645841247E-324
C# вполне удовлетворяет IEEE 754, так что епсилоны ДОЛЖНЫ быть такими.
2Лео: что за херня, причем тут точность вычислений?
Флоат состоит из одного байта экспоненты, одного бита знака и 23 битов мантиссы. Чтобы из этого всего получить число, например, в десятичной системе счисления следует:
1) дописать к мантиссе слева двоичную единичку и перевести ее в десятичную систему счисления.
2) умножить мантиссу на 2^экспонента, воспринимая экспоненту как число от -128 до 127. Хотя тут уже хз, мб из нее еще что-нить вычесть надо, но это совершенно не важно.
3) в зависимости от бита знака умножить результат на +1 или -1.
Все!
Соответственно, можно поставить вопрос: какое ближайшее к нулю положительное число можно записать флоатом. Ответ выше. Кстати, положительные и отрицательные числа симметричны.
Еще можно поставить вопрос, какое ближайшее к 1 положительное число большее 1 можно записать флоатом. Вроде как должно получится 1 + 2^(-23) или 1 + 2^(-24).

Flack_bfsp

Забавно. В VS2003 тоже никаких различий.

bleyman

Охбля. Почитал ваши проги. Большего долбоебства в жизни не видел.
{
int i = Magick_Constant;
float f;
f = *float*)&i);
printf("%f", f);
}
А дальше в течение пятнадцати минут при помощи Магической Константы полностью определяется формат флоата. А заодно и все возможные эпсилоны, которые только могут придти в голову.
Кстати, надо еще учитывать, что некоторые комбинации зарезервированны под nan и +-inf.

shlyumper

Еще можно поставить вопрос, какое ближайшее к 1 положительное число большее 1 можно записать флоатом. Вроде как должно получится 1 + 2^(-23) или 1 + 2^(-24).

Ответ на вопрос какое ближайшее к X положительное число можно записать флоатом не равен тому, что ты написал. Ответ на этот вопрос очень сильно зависит от X. Если ты аккуратно запишешь действия, которые нужны для сложения двух чисел с разными мантиссами, то с удивлением обнаружишь, что число 1+2^(-23) неотличимо от числа 1.
А число 100 неотличимо от числа 100 + 1e-14. А число 10000 неотличимо от 10000 + 1-12. И так далее.
Просто ты, как и многие, путаешь минимальное число, отличимое от 0 (безусловно, равное float.Epsilon в терминах C# и минимальное число, отличимое от X.
Это тебе в подспорье, для проверки таких гипотез на языке C#, соответствующем стандарту IEEE 754.


using System;
namespace Epsilon
{
class Eps
{
[STAThread]
static void Main(string[] args)
{
float eps1, eps;
float x = 1.0F;
eps1 = eps = 1.0F;
while(eps != (float)0.0 && x+eps>x)
{
eps1 = eps;
eps /= (float)2.0;
}
Console.WriteLine("eps+ = " + eps1);
eps1 = eps = 1.0F;
while(eps != (float)0.0 && x-eps<x)
{
eps1 = eps;
eps /= (float)2.0;
}
Console.WriteLine("eps- = " + eps1);
}
}
}

shlyumper

Ты не понимаешь сути проблемы. Внимательно прочитай , специально для тебя сейчас выделю жирным важный момент.

mysha

ну и не на порядок, а всего в 4 раза, и то сами то eps различаются всего в 2 раза, но во втором случае ты выводишь
eps с предыдущего шага, если бы ты это делал в первом случа то выводимые числа сравнялись, а так
этот эффект удобнее наблюдать на другой программе
#include <math.h>
int main{
int i=0;
double a=0;
double eps=1, eps1;
eps=1;
for(i=1;i<100;i++){
eps /= (double)2.0;
printf(" %d= %le, %d!",i,epsdouble)1.0) != double)1.0 - eps) + (eps/(double)2.0;
printf(" %d\n"double)1.0) != double)1.0 + eps) - (eps/(double)2.0;
}
return 0;
}
в первом принтфе 1 не получается дольше.
ЗЫ Кстати я не очень понимаю почему работает твоя программа, если делать в уме, то единица там не должна получиться по крайней мере
во втором случае. Возможно я просто не понимаю округлений при действиях.

shlyumper

Проблема там не в округлениях при действиях, а в сравнении чисел с разной мантиссой. Это вносит свои ограничения. Если поискать eps в районе 0 и в районе 1e10, то его отличие от результатата для 1 может сильно впечатлить.

bleyman

какое ближайшее к 1 положительное число большее 1 можно записать флоатом
Дружок! Где ты в вышеприведенной цытате увидел букву Х?
Просто ты, как и многие, путаешь минимальное число, отличимое от 0 (безусловно, равное float.Epsilon в терминах C# и минимальное число, отличимое от X.
Просто ты, как и многие, невнимательно читаешь чужие посты. Да и вообще немного туповат.
float one = 1;
float eps = (float)Math.Pow(2, -24);
float onemore1 = one + eps;
float delta1 = onemore1 - one;
float onemore2 = one + eps*1.01f;
float delta2 = onemore2 - one;
float onemore3 = one + eps*0.99f;
float delta3 = onemore3 - one;
Console.WriteLine("{0:F10} {1:F10} {2:F10} {3:F10}", onemore1, onemore2, onemore3, eps);
Console.WriteLine("{0:F10} {1:F10} {2:F10}", delta1, delta2, delta3);

1,0000000000 1,0000000000 1,0000000000 0,0000000596
0,0000000000 0,0000001192 0,0000000000
Такой изврат понадобился от того, что врайтлайн отрубает последний десятичный знак.
Итак, как мы видим моя гипотеза о 1 + 10(-24) (или -23, хз как там с округлением) гениально подтвердилась.
2Шурик: видишь ли, на иеее документация платная, а искать ее в другом месте было влом. Особенно что там дохуя говна, наверное, а тут такой тривиальный вопрос.

mysha

ммда и все равно я не понимаю, почему
1.111...11e1==1.0e0 в двоичной записи
либо добавление 1/2^n в какой-то
момент округляет первое число до 1
либо сравнение ведется с точностью до
какой-то констатнты заведомо больше
машинного eps, тогда твои и базилио расчеты неверны -
надо добавлять предполагаемый eps много раз
(а именно 2^ (разница между степенью eps и степенью округления сравнения чтобы
убедиться что ничего не добавляется
Оставить комментарий
Имя или ник:
Комментарий: