Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.09.2013, 07:17   #1
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию Операции с числами.0 очень разных порядков

Здравствуйте.
Занимался линейной регрессией методом наименьших квадратов (y = ax + b) и столкнулся с ситуацией когда операнды очень сильно отличаются (при большом количестве точек), например 1е1 / 1e25. В такой ситуации точность расчетов сильно страдает. long double не помогает. Что можно сделать? Предполагаю что есть какие-то библиотеки с типами для подобных целей.
220Volt вне форума Ответить с цитированием
Старый 06.09.2013, 07:54   #2
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Цитата:
Выделение позиции плавающей точки в отдельный тип

Иногда в задаче требуется производить расчёты с очень большими либо очень маленькими числами, но при этом не допускать их переполнения. Встроенный 8-10-байтовый тип double, как известно, допускает значения экспоненты в диапазоне [-308; 308], чего иногда может оказаться недостаточно.

Приём, собственно, очень простой — вводится ещё одна целочисленная переменная, отвечающая за экспоненту, а после выполнения каждой операции дробное число "нормализуется", т.е. возвращается в отрезок [0.1; 1), путём увеличения или уменьшения экспоненты.

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

Наконец, понятно, что не обязательно выбирать 10 в качестве основания экспоненты. Исходя из устройства встроенных типов с плавающей точкой, самым выгодным представляется класть основание равным 2.
скопипастил отсюда: http://e-maxx.ru/algo/big_integer
rrrFer вне форума Ответить с цитированием
Старый 06.09.2013, 07:56   #3
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

Увы, но таких библиотек не существует. По крайней мере, я таких не знаю. Вам нужно копать в сторону "длинной арифметики". Где-то на форуме, эта тема уже обсуждалась.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
Smitt&Wesson вне форума Ответить с цитированием
Старый 06.09.2013, 12:20   #4
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Smitt&Wesson
длинка на массивах для целых чисел, а вместо дробных юзать самописные дроби.

А то, что я выше писал не подойдет (когда нормализовать будешь таки потеряешь точность ведь..)
rrrFer вне форума Ответить с цитированием
Старый 06.09.2013, 15:25   #5
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Примерно такая ерунда:
Код:
long double a = (133332.0 * 11775194937.75828 - 8888777778.0 * 178214.3044) /
                    (133332.0 * 229486560909910.0 - 8888777778.0 * 8888777778.0);
Win калькулятор говорит: -0,29157768807810781830119421477569
У меня получается: 2.911865009487482219422197198682722 429908e-007
220Volt вне форума Ответить с цитированием
Старый 06.09.2013, 15:51   #6
Smitt&Wesson
Старожил
 
Аватар для Smitt&Wesson
 
Регистрация: 31.05.2010
Сообщений: 13,543
По умолчанию

Цитата:
Сообщение от rrrFer Посмотреть сообщение
Smitt&Wesson
длинка на массивах для целых чисел, а вместо дробных юзать самописные дроби.

А то, что я выше писал не подойдет (когда нормализовать будешь таки потеряешь точность ведь..)
Я не занимался вплотную длинной арифметикой. Это познания, ради эрудиции, не более.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
Smitt&Wesson вне форума Ответить с цитированием
Старый 06.09.2013, 17:11   #7
Somebody
Участник клуба
 
Регистрация: 08.10.2007
Сообщений: 1,185
По умолчанию

Цитата:
Сообщение от 220Volt Посмотреть сообщение
Примерно такая ерунда:
Код:
long double a = (133332.0 * 11775194937.75828 - 8888777778.0 * 178214.3044) /
                    (133332.0 * 229486560909910.0 - 8888777778.0 * 8888777778.0);
Win калькулятор говорит: -0,29157768807810781830119421477569
У меня получается: 2.911865009487482219422197198682722 429908e-007
У меня в Win калькуляторе те же самые 2.911...e-7 получились.
Somebody вне форума Ответить с цитированием
Старый 06.09.2013, 17:42   #8
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Может это какая-то обрезка чисел при ручной вставке (при подсчете знаминателя куда-то исчезают последние разряды). У меня по этой формуле строятся графики, визуально наблюдаю, что при большом количестве исходных данных линия неверна.
220Volt вне форума Ответить с цитированием
Старый 07.09.2013, 17:12   #9
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Спасибо за участие.
220Volt вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Арифметические операции с числами JeFix Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 2 12.10.2012 11:21
Операции с большими числами mrChester Общие вопросы C/C++ 4 08.12.2010 15:22
Borland C 3.1. Операции с 32-х разрядными числами ONiX Помощь студентам 8 23.06.2009 13:49
операции с вещественными числами на ассемблере. Fredy Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 2 28.01.2008 15:43