Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Использование double вместо float, повысится ли точность вычислений? 
:(
    Опции темы
math64
Дата 31.8.2012, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

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



9999E+60 - 64 цифры. У Вас 16 short, 32 байт (полезные данные) в куче, плюс накладные расходы sizeof(super_int) - как я понял, ещё 32 байт, за счёт использования vector<>. Итого 64 байта, если без выравниваний.
У меня будет 214 бит - 7 unsigned, 28 байт (полезные данные). Накладные расходы: usecnt, alloc, length, p - 16 байт, из них 12 перед 28 байтами в куче (40 байт) + 4 байта на стеке. Второе число с тем же значением стоит 4 байта, вне зависимости от значения.

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

В предудущем сообщении исправил код на рабочий, добавил умножение и деление на обычное число и тестовый main();

Это сообщение отредактировал(а) math64 - 31.8.2012, 23:17
PM   Вверх
Нитонисе
Дата 31.8.2012, 23:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(math64 @  31.8.2012,  22:34 Найти цитируемый пост)
Итого 64 байта

Нет. У меня член класса вектор (пустой) занимает 32 байта. Этот размер я замерил функцией sizeof(). Поскольку там тип short int (2 байта), значит зарезервировано 16 ячеек. При заполнении 17-ой будет выделяться новая память, насколько я понимаю. Так вот до этого самого выделения новой памяти я в 32 байтах могу разместить огромадное число 9999E+60. У вас же, насколько я понял, истинное значение числа равняется сумме чисел из массива data. Один элемент массива (unsigned int) занимает 4 байта. В 32 байтах поместится 8 таких чисел. Каждое число максимально равно 4.3E+9, умножив на 8 получим максимальное значение вашего типа на 32 байтах - 34.4Е+9. То есть намного меньше чем у меня. Это не учитывая обслуживающие дополнительные члены (для хранения знака или длины массива).
PM MAIL   Вверх
Нитонисе
Дата 1.9.2012, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Все таки идея с представлением чисел дробями имеет слабые перспективы, так как я что-то не представляю как такие числа возводить в дробную степень (звлечение квадратных, кубических корней).
PM MAIL   Вверх
mes
Дата 1.9.2012, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



Цитата(Нитонисе @  1.9.2012,  08:38 Найти цитируемый пост)
Все таки идея с представлением чисел дробями имеет слабые перспективы, так как я что-то не представляю как такие числа возводить в дробную степень (звлечение квадратных, кубических корней). 

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



--------------------
PM MAIL WWW   Вверх
Нитонисе
Дата 1.9.2012, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(mes @  1.9.2012,  10:44 Найти цитируемый пост)
такое представление чисел имеет  свое название (не могу сходу вспомнить),  есть математика для них и библиотечки попадались.. это я к тому что все это уже придумано и реализовано, гугль должен помочь.. 

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

Это сообщение отредактировал(а) Нитонисе - 1.9.2012, 10:54
PM MAIL   Вверх
math64
Дата 1.9.2012, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

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



Извлечение квадратного корня:
Код

SuperInt x = 999999999U;
SuperInt x2 = x*x*x*x + x*x; // Нужно реализовать полное умножение
SuperInt y = sqrt(x2.toDouble()); // Приближённое значение; Нужен коструктор из double
for( ) {
   SuperInt y2 = (y + x2 / y) / 2U; // Нужно полное деление
   if (y2 == y) break;
   y = y2;
}


Добавлено через 6 минут и 42 секунды
Цитата(Нитонисе @  1.9.2012,  10:53 Найти цитируемый пост)
но корень квадратный, например, из 3 не извлекается

А я сразу про подобное предупреждал. Большинство чисел - иррациональны и даже трасцендентны, и в копмьютере представляются только приближенно.
Хотя некоторые, например, Пи, можно посчитать с любой заданной точностью.
PM   Вверх
Нитонисе
Дата 1.9.2012, 21:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(math64 @  1.9.2012,  20:21 Найти цитируемый пост)
Извлечение квадратного корня:

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

Хотел бы вернуться к названию темы. Где-то в первых постах говорили, что double не может повысить точность по сравнению с float. Но почему? Ведь double имеет точность 15 знаков, а float 7. То есть по идее от операций с double следует и точность бОльшую ожидать. 

Попутно возник вопрос. Если я где-то в вычислениях использовал разнотипные данные (например double умножаю или складываю с float), как это отразится на точности? При выполнении операции данные ведь преобразуются к одному типу. Вопрос - к какому?
PM MAIL   Вверх
math64
Дата 1.9.2012, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

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



Цитата(Нитонисе @  1.9.2012,  21:02 Найти цитируемый пост)
Если я где-то в вычислениях использовал разнотипные данные (например double умножаю или складываю с float), как это отразится на точности?

При умножении double на float, предварительно float преобразуется в double.
Если float представлял число точно (например, 2.f) - результат будет с точностью double.
Если нет - с точностью float.

Использование double НЕ УМЕНЬШИТ точность вычислений - но в некоторых случаях не повысит.
Тоже вычисление корня квадратного уравнения, близкого к 0 - использование double с традиционной формулой даст худший результат, чем вычисление другого корня в float и использование теоремы Виета.
PM   Вверх
Нитонисе
Дата 2.9.2012, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(math64 @  1.9.2012,  21:41 Найти цитируемый пост)
При умножении double на float, предварительно float преобразуется в double.Если float представлял число точно (например, 2.f) - результат будет с точностью double.Если нет - с точностью float.

Допустим мне надо произвести высиления с точностью double. Как их правильно записать:
Код

// вариант 1
double a = 0.123456789;
double b = a * (1/3); // похоже здесь я получу результат a, так как 1 и 3 преобразуются в int?

// вариант 2
double a = 0.123456789;
double b = a * (1.0/3.0); // к какому типу будут преобразованы 1 и 3?



Цитата(math64 @  1.9.2012,  21:41 Найти цитируемый пост)
Использование double НЕ УМЕНЬШИТ точность вычислений - но в некоторых случаях не повысит.

То есть хуже не будет, а скорее всего будет лучше, но не всегда?  smile 

Цитата(math64 @  1.9.2012,  21:41 Найти цитируемый пост)
Тоже вычисление корня квадратного уравнения, близкого к 0 - использование double с традиционной формулой даст худший результат, чем вычисление другого корня в float и использование теоремы Виета.

Но вот вы сразу опровергли предыдущее свое утверждение, показав, что в некоторых случаях double хуже float. Только не понятно почему?


math64, вы предлагали использовать класс Approx для контроля погрешности. Я бы его немного преобразовал.
Код

class my_double
{
  private:
    double v;   // само число
    double dv; // дельта числа
}


При всех математических операциях dv будет меняться. После длительных вычислений я получу некое dv с которым будет более менее удобно работать, выполняя логические действия. Например если v < dv - значит число равно нулю. Сравнивая числа, если fabs(n1.v-n2.v) < max(n1.dv,n2.dv), то числа равны. Только вот не совсем понимаю как мне этот параметр dv вычислять. Подскажите чему он будет равен при стандартных математических операциях (+, -, *, /), а также при возведении числа в дробную степень и применении тригонометрических функций?

Это сообщение отредактировал(а) Нитонисе - 2.9.2012, 11:14
PM MAIL   Вверх
Нитонисе
Дата 2.9.2012, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Да и еще подумал - что тольку от этого параметра dv, если он и сам вычисляется не точно, а с погрешностью...
PM MAIL   Вверх
FCM
Дата 2.9.2012, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Переход к double решает многие проблемы. Можешь проверить, написав свою программу через typedef-псевдоним, в качестве которого выбирать либо float, либо double.
(Есть еще 80-битные и 128-битные floating point, но без веских оснований  не стоит заморачиваться.) 


Это сообщение отредактировал(а) FCM - 2.9.2012, 19:02
PM MAIL   Вверх
math64
Дата 2.9.2012, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

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



Код

double b = a * (1/3);

В результате получишь 0. 1 делится на 3 как целое число, результат = 0.
Нужно
Код

double b = a * (1./3);

или
Код

double b = a * ((double)1/3);


Код

double x2 = 1000. - sqrt(999999.);

лучше чем
Код

float x2 = 1000.f - (float)sqrt(999999.f);

но хуже
Код

float x2 = 1.f/(1000.f + (float)sqrt(999999.f));

а лучше всего
Код

double x2 = 1./(1000. + sqrt(999999.));

Ещё пример:
Нужно посчитать 1 + 1/2 + 1/3 + ... 1/n; где 1/n - намного меньше "компьютерого эпсилон".
Если будешь считать попорядку - начиная с какого-то члена добавление очередного слагаемого не будет изменять сумму, а ведь ряд расходится!
А вот если начнёшь складывать с конца - получишь результат с приемлемой точностью даже с double, не прибегая к точному вычислению с помощью дробей из длинных чисел.

Для контроля за погрешностью я предлагал два врианта:
1. (минимум, максимумум) - абсолютно точно известно, что число не вылезет за пределы диапазона.
Но по мере вычисления диапазон часто быстро расширяется, в то время как чило имеет нормальное распределение с максимумом где-то в середине диапазона.
Поэтому второй вариант:
2. (мат. ожидание, среднее квадратичное отклонение)
С вероятностью 95% (если правильно помню тер.вер.) число находится диапазоне 3 СКО.
Но всё таки всегда будет ненулевая вероятность, что число может оказаться равным 0.


Это сообщение отредактировал(а) math64 - 2.9.2012, 20:24
PM   Вверх
math64
Дата 2.9.2012, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

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



Ну а подсчёт  вероятности такой:
X = x + dx*nx; // nx - случайная величина нормального распределения СКО = 1, среднее = 0
Y = y + dy*ny;
Считая, что dy и dy достаточно малы,
Z = F(X,Y) = F(x,y) + dx*nx*dF/dx + dy*ny*dF/dy + ошибка вычислений.
где dF/dx и dF/dy - частные производные
и вычисляй СКО для
dx*nx*dF/dx + dy*ny*dF/dy + ошибка вычислений,
считая что ошибка вычислений - случайная величина с равномерным распределением (-eps*Z,eps*Z)

Это сообщение отредактировал(а) math64 - 2.9.2012, 20:47
PM   Вверх
Нитонисе
Дата 2.9.2012, 21:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(FCM @  2.9.2012,  18:56 Найти цитируемый пост)
Переход к double решает многие проблемы.

Похоже что так. Единственная для меня проблема здесь в логических операциях с double. Сравниваю так |a-b| < min. То есть если модуль разницы меньше некоего минимального числа, то a = b. Весь вопрос в том что выбрать за минимальное число. До сих пор работая с double я брал число 0.001. Для моих задач чаще всего хватало, но не всегда. Хотелось бы как-то обоснованней назначать его. Вот если бы параллельно основным вычислениям шел бы и расчет погрешности, то эту погрешность я бы и принимал в качестве минимальной разницы чисел.


math64
Код

double b = a * (1./3);
double b = a * ((double)1/3);

Это две эквивалентные записи? В первом случае ведь единица приводится к double неявно. Может она в вычислениях к float приведется? И почемы вы тройку не приводите к double? В операции деления она автоматически преобразуется в double, так как единица принадлежит этому типу? А что если не преобразуется? А если к double привести тройку, а единицу нет (1/(double)3) - то тройка преобразуется к int?

Правильна ли ниже запись цикла, где надо считать с точностью double, но счетчик цикла типа int.
Код

double a;
for (int i=0; i<10; i++) a *= ((double)i/3); //


Цитата(math64 @  2.9.2012,  20:23 Найти цитируемый пост)
Ещё пример:Нужно посчитать 1 + 1/2 + 1/3 + ... 1/n; где 1/n - намного меньше "компьютерого эпсилон".Если будешь считать попорядку - начиная с какого-то члена добавление очередного слагаемого не будет изменять сумму, а ведь ряд расходится!А вот если начнёшь складывать с конца - получишь результат с приемлемой точностью даже с double, не прибегая к точному вычислению с помощью дробей из длинных чисел.

Так ведь и если с конца начать складывать, то до некоторого числа сумма будет равняться нулю.

Цитата(math64 @  2.9.2012,  20:23 Найти цитируемый пост)
Для контроля за погрешностью я предлагал два врианта:1. (минимум, максимумум) - абсолютно точно известно, что число не вылезет за пределы диапазона.
С диапазоном просто чуть сложнее работать, потому что чтобы получить само число - надо выполнять среднее арифметическое. Смысла нет отводить две переменные под верхний и нижний диапазон, потому что они равноудалены от среднего значения. Другое дело, что будь-т эти диапазоны, будь-то абсолютная погрешность по моему вараинту - вычисляются. А коли они вычисляются, значит тоже будет присутствовать погрешность. А коль там числа крайне малые, то думается что и погрешность вычисления этой самой погрешности будет значительна.
PM MAIL   Вверх
FCM
Дата 3.9.2012, 07:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Нитонисе @  2.9.2012,  21:18 Найти цитируемый пост)
Похоже что так. Единственная для меня проблема здесь в логических операциях с double. Сравниваю так |a-b| < min. То есть если модуль разницы меньше некоего минимального числа, то a = b. Весь вопрос в том что выбрать за минимальное число. До сих пор работая с double я брал число 0.001. Для моих задач чаще всего хватало, но не всегда. Хотелось бы как-то обоснованней назначать его. Вот если бы параллельно основным вычислениям шел бы и расчет погрешности, то эту погрешность я бы и принимал в качестве минимальной разницы чисел.


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

Это сообщение отредактировал(а) FCM - 3.9.2012, 07:54
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

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

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


 




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


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

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