
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.134.105.118] |
![]() |
|
Страницы: (4) [1] 2 3 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здравствуйте!
Если числа умножать, то возможно произойдёт переполнение. Как его обработать? Например функция, возвращающая максимальное число разрядов, с указанным основанием системы счисления, для типа double. ![]() ![]() int get_double_digits( int b = 10 ) { int ret = 0; double x = 1; // умножаем до упора for(;;) { x = b * x; ret++; } return ret; } А когда нужно прервать цыкл? Интересуют стандартные инструменты. Возможно есть какие-то функции, умножающие с проверкой переполнения? Библиотеки, для сверхбольших чисел не волнуют! Добавлено Есть функция matherr и там даже есть код ошибки overflow. Но кому её указывать? И будет ли она вызвана при умножении? В прочем, похоже, это не тот случай. Слишком неудобен здесь callback. Добавлено Меня интересует тот момент, когда число, начинает терять точность, отбрасывая младшие разряды. Вот например число 9.999 может быть востановлено, а число 9.99999999999999999 превращается в 10. По этому я взялся именно умножать, на основание нужной системы счисления. |
Сообщ.
#2
,
|
|
|
1.Сидеть и на каждое из сотен умножений молиться на переполнение - по-моему глуповато и стандартом не предусмотрено.
2.Я бы на конкретный случай так залепил: ![]() ![]() if( (long double)b*(long double)x>1e4000 ) тру-ля-ля; // не 1e4000 конечно, но суть в этом, типа DBL__MAX else x = b*x; |
Сообщ.
#3
,
|
|
|
Была тут недавно тема: Как включить эксепшен для переполнения переменных?
|
Сообщ.
#4
,
|
|
|
Тоже вариант. Но почему оператор ">"? Если максимальное значение, значит число не может быть больше.
С другой стороны, при переполнении, биты теряются и в результате получается битовая каша. Если процессор проверяет переполнение, то должно быть nan. Но функция _isnan не детектит! |
Сообщ.
#5
,
|
|
|
Цитата Eric-S @ Есть функция matherr и там даже есть код ошибки overflow. Но кому её указывать? И будет ли она вызвана при умножении? В прочем, похоже, это не тот случай. Слишком неудобен здесь callback. Не будет. Это только для целочисленных. Цитата Славян @ 2.Я бы на конкретный случай так залепил: Выходные параметры надо проверять и выдавать ошибку если они вызывают переполнение. Цитата Славян @ .Сидеть и на каждое из сотен умножений молиться на переполнение - по-моему глуповато и стандартом не предусмотрено Можно исключения отлавливать. Вот только тут вопрос что дальше делать? Давно известно несколько подходов. Забить на ошибки. Сделать расчёты так чтобы они были нечувствительны к ошибкам. т. е. устойчивы. Проверить входные параметры и выставить false как результат функции. Проверить входные параметры и выставить исключение. В любом случае ошибку должен обрабатывать решатель, т.е основной код программы. Но так как в большинстве случаев вообще не ясно что делать то выполнение программы прекращается с выкидом ошибки. |
Сообщ.
#6
,
|
|
|
Цитата Pavia @ Вот это, думаю, лучшее решение! Беспокоитесь, Eric-S, что будет переполнение - завóдите не 'x', а '_1x', в коем храните 1/x, и тогда уже не умножаете, а без проблем делите на 10. А в итоге - смотрите, получили 0 или нет. Если "да", то это ваш NaN и тут уже раскручиваете карусель. Сделать расчёты так чтобы они были нечувствительны к ошибкам. т. е. устойчивы. |
Сообщ.
#7
,
|
|
|
Цитата Мяут-Настоящий @ Была тут недавно тема Спасибо... Но там чуток другое. У него же short. И он может взять long, которого заведомо хватит для результата, а потом его проверить константами на переполнение. А мне же интересен double или даже long double. А что может быть заведомо больше? Цитата Pavia @ Не будет. Это только для целочисленных. Спасибо. Я только описание прочитал. Цитата Pavia @ Забить на ошибки. Это не мой подход. Ошибки должны долбать по совести. И желательно посильнее. Цитата Pavia @ Можно исключения отлавливать. Вот только тут вопрос что дальше делать? А нет их! Всё тихо. Цитата Pavia @ Проверить входные параметры и выставить false как результат функции. Я привел пример функции. Любые входные параметры, ранее или позднее, приводят к переполнению. Хе-хе. При этом входные параметры заведомо корректны. Цитата Pavia @ В любом случае ошибку должен обрабатывать решатель, т.е основной код программы. Это как раз понятно. А вот как узнать, что настал тот самый случай? Вот, например, в операционке, встроена програма "calc.exe". Когда я над ней глумлюсь, она порой заявляет, что дальше считать не будет, ибо получается слишком большое число. Но, именно что явно объявляет, а не падает или не выдаёт хрень. |
Сообщ.
#8
,
|
|
|
Eric-S
"calc.exe" использует длинные числа и кучу if. Добавлено Цитата Eric-S @ А нет их! Всё тихо. Так замени числа с плавающий точкой на целые числа. К примеру "long long int". Просто для плавающих точек переполнение нет. Зато есть исключение забыл что за исключение но оно не информативное там надо уже конкретно проверять числа. |
Сообщ.
#9
,
|
|
|
Цитата Славян @ Вот это, думаю, лучшее решение! Беспокоитесь, Eric-S, что будет переполнение - завóдите не 'x', а '_1x', в коем храните 1/x, и тогда уже не умножаете, а без проблем делите на 10. А в итоге - смотрите, получили 0 или нет. Если "да", то это ваш NaN и тут уже раскручиваете карусель. Это была первая мысль. Даже точнее нулевая. Но число-то с плавающей точкой и делить его можно так же до посинения. Я может чего-то путаю, но там же есть, всякие мантиссы и экспаненты. Соответственно и максимально возможное число, будет, гэ-ха-эм, не совсем корректное. В прочем, попробовал. Думал, что оно меня приятно удивит. По идее, я должен получить 16 если задам 10 на входе. Но получил 309. |
Сообщ.
#10
,
|
|
|
Eric-S
Давай так. Тебе что надо get_double_digits написать или ошибки научиться обрабатывать? |
Сообщ.
#11
,
|
|
|
Цитата Pavia @ "calc.exe" использует длинные числа и кучу if. Да вроде короткие. За максимальные значения не выскакивал. А куча if... не страшно. Цитата Pavia @ Так замени числа с плавающий точкой на целые числа. Мне нужно именно long double. В std::numeric_limits есть функция возвращающая число разрядов для основания системы счисления равным 10. То есть для десятичной системы. А я хочу получить для любой... От 2 (двоичной) до 36-ричной. Не знаю, может надо не через переполнение, а как-то по иному вычислять. Пока не придумался алгоритм. Добавлено Цитата Pavia @ Eric-S Давай так. Тебе что надо get_double_digits написать или ошибки научиться обрабатывать? И того и другого, можно даже без хлеба. Добавлено Упс. Мне похоже, чуток не то надо. С учётом экспоненты оно шибко круто набирает высоту. А можно ли как-то получить отдельно значение мантиссы и экспоненты? |
Сообщ.
#12
,
|
|
|
http://www.cplusplus.com/reference/cmath/frexp/
Добавлено Цитата Eric-S @ NaN - это не переполнение.Но функция _isnan не детектит! http://www.cplusplus.com/reference/cmath/isinf/ Добавлено P.S. Не знаю как сейчас, а раньше MSVC не поддерживал 80-битные числа с плавающей точкой, и long double бы в нем синонимом double. В MSVC бесконечность числа можно проверить функцией _finite |
Сообщ.
#13
,
|
|
|
Цитата Eric-S @ Да. Можно. К примеру, через наложение структур. Но это емкий процесс, как для такой задачи, хотя, кому как.А можно ли как-то получить отдельно значение мантиссы и экспоненты? Написал по памяти, мб и ошибся где-то, но смысл в этом. ![]() ![]() #include <stdio.h> union ParsedDouble { double dbl; // значение Double struct { unsigned __int64 m : 52; // мантисса unsigned int e : 11; // экспонента unsigned int s : 1; // знак } d; }; void main() { ParsedDouble A; // Буфер для перевода double B; // Ваша переменная Double B = 32.680765433; // Ваше число // Переводим A.dbl = B; printf("Мантиса: %I64d \n", A.d.m); printf("Экспонента: %u \n", A.d.e); if (A.d.s == 1) printf("Число отрицательное."); else printf("Число положительное."); } |
Сообщ.
#14
,
|
|
|
Цитата simsergey @ К примеру, через наложение структур. Насколько я знаю, эта структура, может изменятся. Есть даже функции для изменения точности. В прочем, если размер мантиссы жестко фиксирован, то нужное значение, я могу вбить в код магическим числом. И сократить вычисления. Ага. Я её уже смотрел. Думал что подойдёт, но не очень понял, что она делает. Сейчас попробовал подобратся глубже... И всё равно туплю. Возвращает число, от 0.5 до 10. Дополнительно указывает... Какое-то число. Решил потестировать. Понятнее не стало. Хотя... ![]() ![]() double x = 1; int n = 0; double r = frexp( x, &n ); x=1, r=0.5, n=1. x=2, r=0.5, n=2. x=4, r=0.5, n=3. x=8, r=0.5, n=4. x=10, r=0.265, n=4. Похоже что n - экспонента, но основания двойки. Ндяс. Всё куда интереснее, чем казалось. Ну да верно, ведь число-то хранится в двоичной системе. Уф, откровение! А вот что делать с этим дальше, в практическом смысле... Это же надо как-то пересчитывать, для нужного основания. |
Сообщ.
#15
,
|
|
|
Цитата Eric-S @ Я так не думаю Насколько я знаю, эта структура, может изменятся. ![]() Цитата Eric-S @ Тип double в с++ использует двоичное основание. Не зависимо того, что вы с ним будете делать, он как хранился по основанию 2 так и будет храниться, ему как выделялось 52 бита под мантису, так и будет выделяться..Например функция, возвращающая максимальное число разрядов, с указанным основанием системы счисления, для типа double. Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. ![]() |