
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.86] |
![]() |
|
Сообщ.
#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. Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. ![]() |
Сообщ.
#16
,
|
|
|
Eric-S
Тема большая поэтому всё рассказать не получиться. Числа с плавающей точкой состоят из мантиссы и экспоненты. И ещё бывают децентрализованные и нормализованные. Проблема в том что перевод чисел из одной системы счисления в другую идут с ошибками округления. Поэтому тут надо будет ещё аккуратно. А ещё числа бывают двоичные и десятичные. Десятичные конечно редкость. Формат вывода чисел бывает с фиксированной точкой бывает научный (-d.ddd...E+ddd...) Мантиса. Точность мантисы. Точность можно вычислить http://en.wikipedia.org/wiki/Machine_epsil...n_using_C.2B.2B Но гораздо проще воспользоваться константой. В Си есть библиотека констант. std::numeric_limits Но так как константу нельзя записать числами из за погрешности при переводи из одной системы счисления(СС) в другую СС. Поэтому машинную точность определяют через функцию power EpsSingle=power(2,-24); EpsDouble=power(2,-53); Экспонента. Тут уже сказали что будет inf(бесконечность), а не NaN(не число). Пересчёт констант из одной СС в другую. Константы легко пересчитать для разной СС. 2^13=10^x log_10(2^13)=x Или x=log(2^13)/log(10) Что касается ловли ошибок. У чисел с плавающей точкой есть разные классы ошибок. http://www.openwatcom.org/index.php/Math_e...handling_on_x87 http://msdn.microsoft.com/en-us/library/wi...9(v=vs.85).aspx Тип ошибок который стоит обрабатывать надо просто установить. http://msdn.microsoft.com/en-us/library/c9...6h(VS.100).aspx По умолчанию насколько помню включено деления на 0 и неправильная команда. Некоторые графические библиотеки любят работать с определённым типом чисел нормированные/денормальными. По поводу общей концепции обработки ошибок. Такого описания я не видел. В численных методах есть два движение. 1. Безошибочные вычисления. 2. Устойчивые к ошибкам вычисления. Без ошибочные вычисления. Для предотвращения переполнения используют длинных числа. Вместо десятичный дробей используют рациональных числа. В базах данных для финансовых вычислений все исчисления идут с 10 числами без конвертации в двоичные. Стив Макконел даёт эту тему тоже в сколь. Хотя общие рекомендации такие. 1. Проверка входных и выходных параметров функции. 2. Выделения памяти в общем коде и передачу обработчику уже выделенного диапазона памяти. 3. Сообщения результата о ошибке ниже следующему обработчику для принятия решения. Лично мне результат ошибки нравиться передавать через return, а не вызывать исключение. |
Сообщ.
#17
,
|
|
|
Цитата simsergey @ Цитата Eric-S @ Я так не думаю Насколько я знаю, эта структура, может изменятся. ![]() Утверждать и настаивать не буду. Просто, мне казалось, что она компиляторо и платформозависимая. Цитата simsergey @ double в с++ использует двоичное основание. Конечно же. Ведь компьютер бинарный. Моё удивление происходило из того, что я , как-то не подумал о столь очевидном факте. Точнее, даже и не задумывался. Цитата simsergey @ Если я Вас не так понял, мб переформулируете, или другой приведете пример, что же должна делать функция.. ![]() Отдельный момент, который всплыл при обсуждении, вы поняли правильно. И ваш вариант со структурой, мне гораздо удобнее, чем функция frexp(). А конкретная функция, должна возвращать число разрядов, которые поместятся в мантиссу без усечения. Если мантисса точностью 52 бита, то в двоичной системе, это 52 разряда. Но в 16-ричной это 13 разрядов. А функция должна вернуть число разрядов мантиссы, для системы счисления, с основанием b. |
Сообщ.
#18
,
|
|
|
Цитата Eric-S @ Насколько я знаю, эта структура, может изменятся. Есть даже функции для изменения точности. Структура может изменяться. Но на самом деле есть стандарт IEEE-754 который и был принят для того чтобы числа не изменялись и на разных архитектура имели одинаковый формат. Что касается функции изменения точности, так она только зануляет лишние биты из числ в формате IEEE-754. Так что ей пользоваться не стоит. Вообщем она устаревшая. И такой было чуть ли не во время создания Си. |
Сообщ.
#19
,
|
|
|
Цитата Pavia @ Числа с плавающей точкой состоят из мантиссы и экспоненты. Ага, я это уже давно знаю. Выше, даже приведена структура представления в памяти. Цитата Pavia @ И ещё бывают децентрализованные и нормализованные. Об этом только слышал. Что за зверь, не представляю. Цитата Pavia @ Проблема в том что перевод чисел из одной системы счисления в другую идут с ошибками округления. Поэтому тут надо будет ещё аккуратно. Ну, это известная проблема. В прочем она решаемая. Я собственно уже давно сделал класс для конвертации числа с плавающей точкой в строку, причём с указанной системой счисления. С округлением, действительно, пришлось туго. Но уже всё норм. А вот сейчас, хотел к нему прикрутить дополнительные плюшки. Чтоб лимит знаков, выставлялся автоматически. Дополнительный параметр, раздражает. Цитата Pavia @ А ещё числа бывают двоичные и десятичные. Десятичные конечно редкость. Шутите? Угу... Я так и подумал! Знаем, конечно же, и постоянно пользуемся. двоичная и шестнадцатеричная для компа, десятичная для денег, 12 и 24 для часов, 7 ричная для дней недели... И с основанием n, для прикола. Цитата Pavia @ Формат вывода чисел бывает с фиксированной точкой бывает научный (-d.ddd...E+ddd...) Угу. Знаемс тоже. Кстати, давно мучит вопрос, а как в экспоненциальной записи, оформить 16-ричное число? Или научная исключительно для 10-ричной? Это, если конечно же не использовать специальный значок юникода, а писать латинскую e. Цитата Pavia @ Мантиса. Точность мантисы. Точность можно вычислить http://en.wikipedia.org/wiki/Machine_epsil...n_using_C.2B.2B Но гораздо проще воспользоваться константой. В Си есть библиотека констант. std::numeric_limits Но так как константу нельзя записать числами из за погрешности при переводи из одной системы счисления(СС) в другую СС. Поэтому машинную точность определяют через функцию power EpsSingle=power(2,-24); EpsDouble=power(2,-53); Опс... Это интересно... Так, побегу читать. |
Сообщ.
#20
,
|
|
|
Цитата Eric-S @ Это, если конечно же не использовать специальный значок юникода, а писать латинскую e. Видел используют e махонькую для отделения экспоненты. А в числах там буквы все большие. А вообще тоже интересно общепринятый формат. Добавлено Цитата Eric-S @ Шутите? Угу... Я так и подумал! Знаем, конечно же, и постоянно пользуемся. двоичная и шестнадцатеричная для компа, десятичная для денег, 12 и 24 для часов, 7 ричная для дней недели... И с основанием n, для прикола. В VAX компьютерах была десятичная арифметика реализована прямо в процессоре. |
Сообщ.
#21
,
|
|
|
О! Кажись нашел интересненькое. с std::numeric_limits я уже знаком, но там чего-то не то. Особенно у старого vs 2010.
А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак. Ладненько, теперь надо подумать, как его пересчитать для нужной системы счисления. Для 2-ичной, я разделил на 1, для 16 ричной, я разделил на 4. Но забавно, для 10, я тоже должен разделить на 4 и получить 13. Тогда как точно знаю, что у меня влазит 16 разрядов. |
Сообщ.
#22
,
|
|
|
Цитата Eric-S @ Но забавно, для 10, я тоже должен разделить на 4 и получить 13. Тогда как точно знаю, что у меня влазит 16 разрядов. Не делить. Я же привел пример считаешь через логарифмы а потом округляешь. На само деле все 17 разрядов. |
Сообщ.
#23
,
|
|
|
Цитата Pavia @ Поэтому машинную точность определяют через функцию power EpsSingle=power(2,-24); EpsDouble=power(2,-53); ... Пересчёт констант из одной СС в другую. Константы легко пересчитать для разной СС. 2^13=10^x log_10(2^13)=x Или x=log(2^13)/log(10) Верно. Я же побежал проверять и не дочитал. Но, ха-эм... с функциями непонятки, кто из них кто? Да и математику, давно уж забыл. Сейчас со скрипом вспоминал, что вообще такое логарифм. А уж какими функциями возводить число в степень или искать логарифм, никогда и не ведал. Значит power() это возведение a, в степень b? А log() это логарифм... Упс, а у него один параметр? Не, надо лезть в справочник. Не знал не знал и забыл. |
Сообщ.
#24
,
|
|
|
А разве порядок не выясняется через (int)(double >> 52)? (сейчас не проверю)
С мантиссой в моей Double как Integer разобрались... |
Сообщ.
#25
,
|
|
|
Eric-S
Цитата Eric-S @ Значит power() это возведение a, в степень b? А log() это логарифм... Упс, а у него один параметр? power возведение в степень. Всё верно. Логарифм да. Цитата Eric-S @ Не, надо лезть в справочник. Не знал не знал и забыл. Также уже забыл. Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78.. По поводу логарифма по произвольному основанию надо посмотреть справку в модуле math должно быть что-то. Но можно реализовать и самому через log или ln или через логарифм с любым основанием. log(x)/log(b) где b основание. ln(x)/ln(b) где b основание. |
Сообщ.
#26
,
|
|
|
Pavia, благодарю! у меня получилось.
|
Сообщ.
#27
,
|
|
|
Цитата Pavia @ Но можно реализовать и самому через log или ln или через логарифм с любым основанием. log(x)/log(b) где b основание. ln(x)/ln(b) где b основание. Круто. Это уже выходит за рамки моих знаний. Но оно работает. Спасибо. Цитата Pavia @ На самом деле все 17 разрядов. Ха-эм. На практике у меня 16. Если ставлю 17, то начинаются жуткие проблемы с округлением. Например в последнем разряде, появляются артефакты. А вот написанная функция говорит, что 15. Я правда ткнул мантиссу 52 бита. ![]() ![]() #include <cmath> #include <iostream> int main() { // основание системы счисления int b = 10; // размер мантиссы auto m = std::pow( 2.0, LDBL_MANT_DIG - 1 ); // число разрядов auto d = std::log( m ) / std::log( static_cast< long double >( b ) ); std::cout << "digits: " << d << std::endl; return 0; } Добавлено Вот получившаяся функция. ![]() ![]() // возвращает максимальное число разрядов для указанной системы счисления std::size_t get_digits_count( unsigned int b ) { // число разрядов return static_cast< std::size_t >( std::log( std::pow( 2.0, LDBL_MANT_DIG - 1 ) ) / std::log( static_cast< long double >( b ) ) ); } Это альтернативное решение, не касающееся сабжа. А если вернутся к переполнению, то можно проверять, сравнивая число с максимально допустимым значением std::pow( 2.0, LDBL_MANT_DIG - 1 ). Всем спасибо. Тему закрываю. |
Сообщ.
#28
,
|
|
|
Цитата Pavia @ У вас смесь из математики и программирования. Дела таковы:Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78.. Математика: ln-натуральный, log-общий Программирование: log-натуральный, ln-нет такого (букв мало?) |
Сообщ.
#29
,
|
|
|
Цитата Славян @ Цитата Pavia @ У вас смесь из математики и программирования. Дела таковы:Насколько помню log - логарифм по основанию 10, ln - натуральный логарифм, другими словами логарифм по основанию e=2.78.. Математика: ln-натуральный, log-общий Программирование: log-натуральный, ln-нет такого (букв мало?) С какой-то радости, математику смешивают с программированием? Это уже давно, две разные науки. Лично мне, функциями понятнее. Даже если я тех функций не знаю. Но по контексту можно догадатся. А вот матзначки, вынесут мой несчастный мозг... |
Сообщ.
#30
,
|
|
|
Цитата Eric-S @ Это сильно завязанные науки. Вот log знают все, это общее, это даже начало слова. Но математикам лень использовать общий логарифм, потому они и ввели ln-для натурального (мега-сокращение,да!?), а lg-для десятичного. А вот программистам две буквы - ну уж слижком коротко (в ассемблере и то - редкость), а логарифм нужен. Потому и решили, что пусть log-натуральный, а log10 - десятичный. С какой-то радости, математику смешивают с программированием? Это уже давно, две разные науки. |
Сообщ.
#31
,
|
|
|
Программистам букав мало. Две буквы, это всего pow( 26, 2 ), а три буквы уже pow( 26, 3 ). Хотя последнего тоже мало. Не даром ведь придумали всякие namespace.
И очень жаль, что математики, по прежнему используют всякие ln lg и подобное. Треба водить единый стандарт. |
Сообщ.
#32
,
|
|
|
Славян
Цитата Славян @ Математика: ln-натуральный, log-общий Программирование: log-натуральный, ln-нет такого (букв мало?) В разных языках программирования по разному поэтому могу путать. |
Сообщ.
#33
,
|
|
|
Цитата Pavia @ "Децентрализованные" - это что-то доселе невиданное. Денормализованные. И ещё бывают децентрализованные |
Сообщ.
#34
,
|
|
|
Цитата trainer @ "Децентрализованные" - это что-то доселе невиданное. Денормализованные. Да. Авто проверка языка подводит. Без неё у меня в каждом слове по ошибке. |
![]() |
Сообщ.
#35
,
|
|
Вообще-то Стандарт языка определяет систему счисления для представления только целых типов данных. Что касается типов с плавающей точкой, то он рекомендует, но не обязывает, следовать стандарту IEC-559 (он же IEEE-754), а там обязывания какой-то конкретной системы счисления нет. В интерфейсах <cfloat> (float.h) и <limits> определяются константы FLT_RADIX и std::numeric_limits<>::radix. Вот их и надо пользовать, если очень интересно. Последний, согласно Стандарту, для целочисленных типов должен возвращать 2.
Добавлено Цитата Eric-S @ Порядок числа обязательно должен указываться со знаком, поэтому E, определяющая экспоненту однозначно отделяется от E, являющейся частью мантиссы, наличием после себя + или -. Кстати, давно мучит вопрос, а как в экспоненциальной записи, оформить 16-ричное число? Или научная исключительно для 10-ричной? Это, если конечно же не использовать специальный значок юникода, а писать латинскую e. Добавлено Цитата Pavia @ В НИИ системотехники, где я имел удовольствие одно время работать, разрабатывался на заказ троичный FPU. В VAX компьютерах была десятичная арифметика реализована прямо в процессоре. Добавлено Цитата Eric-S @ В соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных. А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак. |
Сообщ.
#36
,
|
|
|
Eric-S, я вспомнил, что немного забыл раньше
![]() На самом деле, в double число хранится не в явном виде мантисы и порядка (экспоненты), в связи с неявной единицей. Для получения реального значения мантисы, нужно сдвинуть вправо мантису с занесением в первый разряд единицы. И правкой порядка. Порядок вроде бы хранится в "дополнительном коде". Если Вам интересен этот вариант, можно развить )) Напомнили: Цитата Qraizer @ Добавлено 40 минут назад Цитата (Eric-S @ Сегодня, 12:54) А вот константа DBL_MANT_DIG возвращает размер мантиссы, для типа long double. Если я конечно правильно понял. И это число, у меня 53. Ха-эм. Ладно, вычтем битик, на знак. В соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных. |
Сообщ.
#37
,
|
|
|
Да ладно. Меня уже всё устраивает. С двоичным представлением, возится лень. Оно мне сейчас не требуется. Но буду иметь в виду.
Разрядность я получил. Как сделать проверку узнал. По ходу выяснилось, что она не нужна. Ну да ладно. Система счисления, у меня задаётся опционально. Какая она там по дефолту, уже не важно. Мой класс делает любую от 2-ричной, до 36-ричной включительно. Сейчас загрузился автоматическим выбором, когда выводить в простом формате, а когда в научном с экспанентой. Добавлено Цитата Qraizer @ Порядок числа обязательно должен указываться со знаком, поэтому E, определяющая экспоненту однозначно отделяется от E, являющейся частью мантиссы, наличием после себя + или -. О! Значит знак обязателен. Это хорошо. Я так и сделал. А нолик обязателен или нет? А то я его выбросил. 1.2e+23 или 1.2e+023 |
Сообщ.
#38
,
|
|
|
Успехов в коде
![]() Цитата Eric-S @ Не забывайте про производительность. Хотя, железо походу не может обеспечить обработку разных систем счисления напрямую.. Интел подкачал С двоичным представлением, возится лень. ![]() |
Сообщ.
#39
,
|
|
|
Цитата Qraizer @ обязывания какой-то конкретной системы счисления нет. В интерфейсах <cfloat> (float.h) и <limits> определяются константы FLT_RADIX и std::numeric_limits<>::radix. Вот их и надо пользовать, если очень интересно. Последний, согласно Стандарту, для целочисленных типов должен возвращать 2. о! Вот даже как. Это везде, куда я вбивал магические двойки, надо подставлять сию константу? Добавлено Цитата simsergey @ Успехов в коде ![]() Спасибо. Вам того же! Добавлено Цитата simsergey @ Не забывайте про производительность. Хотя, железо походу не может обеспечить обработку разных систем счисления напрямую.. О производительности помню. Хотя, частенько оптимизации откладываю. Особенно в плюшках. Нет уж, прокачать обычной алгеброй, куда надёжнее. Особенно когда есть желание поизвращатся. А стандартный функционал отсутствует вообще. Добавлено Цитата Qraizer @ соответствии с IEEE один самый старший бит в 32-х и 64-битных форматах является неявным. Его значение всегда 1 для нормализованных, бесконечностей и нечисел и всегда 0 для денормализованных и нулей. Первые отличаются от вторых смещённым порядком. Порядки 0 и максимальный зарезервированы для спец.форматов, от 1 до макс-1 - для нормализованных. Ха-эм. Так мне что, два бита отнимать? Сколько там реально используется для хранения числа? |
Сообщ.
#40
,
|
|
|
Цитата Eric-S @ А почему 2?Так мне что, два бита отнимать? Сколько там реально используется для хранения числа? В Double реально хранится 52 бита мантисы. При арифметических операциях процессор при рассчетах подразумевает, что их 53, дорисовывая слева 1. К примеру, в памяти 010010101010101, а цп эту запись интерпретирует как 1010010101010101. Но в памяти хранится 52 бита. Почему 2 отнимать? Знак? Так Double занимает 64 бита, из которых: знак числа, порядок и мантиса. Знака мантисы - нет, есть "знак числа", а знак порядка записан в 11 битах порядка, и т.к. порядок представлен в ДК (дополнительный код), то знак порядка хранится там же (не совсем отдельным битом). Double Wiki Для справки, есть еще тип Float, работает по тому же принципу, но предоставляет меньшую точность. Взамен - занимает меньше памяти. Мантиса: 23 бита. Порядок: 8 бит. Знак: 1 бит. |
Сообщ.
#41
,
|
|
|
В десятичных константах в формате с плавающей точкой знак + после буквы e можно не писать.
IEEE-754 задаёт 4 представления с разным количеством бит 16 / 32 (float) / 54 (double) / 128. В C и C++ используются два средних. В качестве long double используется 10-байтовое временное представление процессоров i387. Хотя некоторые компиляторы используют 128-битный формат IEEE |
Сообщ.
#42
,
|
|
|
Цитата amk @ А расскажите поподробнее, а? В качестве long double используется 10-байтовое временное представление процессоров i387. Хотя некоторые компиляторы используют 128-битный формат IEEE |
Сообщ.
#43
,
|
|
|
Начиная отсюда: http://ru.wikipedia.org/wiki/IEEE_754-2008 и далее по ссылкам в тексте.
Добавлено ЕМНИП, в первоначальной версии этого стандарта таки фигурировали 80-битные числа. |
Сообщ.
#44
,
|
|
|
Угу. Стандарт, конечно хорошо. Но я, в конкретном компилере имею float и double. Причом есть long double который sizeof(long double) 64.
А где половинная и учетверённая точность? Добавлено Цитата amk @ В десятичных константах в формате с плавающей точкой знак + после буквы e можно не писать. Ну, это меня интересовало, как раз для не десятичной записи. Например шестнадцатиричной, в которой буква "e" имеет значение 14. И в этом случае, без плюсика не обойтись. "0XFFe+10" Кстати, а в какой системе счисления нужно записывать порядок? В той же или десятичной? Добавлено Цитата simsergey @ А почему 2? Так я и спрашивал, нужно ли что-то отнимать и если да, то сколько. С форматом уже разобрался, спасибо! А вот прогулявшись по описанием стандартов, так и не понял, как записывать 0, NaN и +q и -q? Я так понял, это денормализованные значения? |
Сообщ.
#45
,
|
|
|
Цитата trainer @ Нет, частью стандарта IEEE-754 это представление никогда не было. Оно не соответствует обобщённому формату. Это фсего лишь внутреннее представление чисел в арифметическом сопроцессоре i8087. Более того, судя по ранней документации на i8087 даже инженеры Intel изначально не предполагали использовать его в качестве самостоятельного типа данных (хотя для возможности сохранения состояния процессора предусмотрели возможность его чтения/записи). Просто процессор должен был иметь возможность работать не только с плавающими числами, но и с целыми - 16/32/64 бит - и десятичными - до 20 цифр (включая знак). ЕМНИП, в первоначальной версии этого стандарта таки фигурировали 80-битные числа. Добавлено Да, словосочетание "переполнение мантиссы" для чисел с плавающей точкой не совсем верно. В этом случае мантисса просто сдвигается на один разряд вправо (больше не надо) и к порядку добавляется единица. И вот тут может произойти переполнение порядка. Процессоры с полной реализацией арифметики IEEE выдают результат равный ±∞ (все разряды характеристики ?— единицы, все видимые разряды мантиссы — нули). Кроме того сопроцессор может сформировать при этом прерывание. Те процессоры, которые не поддерживают арифметику на таком уровне просто генерируют прерывание. |
Сообщ.
#46
,
|
|
|
Цитата amk @ Да, словосочетание "переполнение мантиссы" для чисел с плавающей точкой не совсем верно. В этом случае мантисса просто сдвигается на один разряд вправо (больше не надо) и к порядку добавляется единица. На счёт некоректности фразы - согласен. Но меня интересовал именно этот момент, когда происходит сдвиг, при заполненной мантиссе. И младшие разряды в мантиссе теряются. Понятно, что порядок растёт всё время. Но в начале, мантисса просто увеличивает значение, а потом происходит её переполнение, которое нейтрализуется сдвигом мантиссы и изменением порядка. А на счёт словосочетания, тем более в заголовке. Предложите корректный и я поправлю. Добавлено И ещё ссылочку. Я тут уже спрашивал про денормализованные числа. Всё же, ради интереса, решил разобратся. И нашел тут кучу полезного. http://softelectro.ru/ieee754.html |
Сообщ.
#47
,
|
|
|
Цитата Eric-S @ Понятно, что порядок растёт всё время. Но в начале, мантисса просто увеличивает значение, а потом происходит её переполнение, которое нейтрализуется сдвигом мантиссы и изменением порядка. Это справедливо только для частных случаев, когда мантиссы операндов (слагаемых или множителей) имеют ограниченное число двоичных знаков - для целых чисел и конечных двоичных дробей (целых чисел, деленных на некоторую степень 2). Но подавляющее число десятичных дробей, представляются бесконечными двоичными дробями, и соотв-но, 1) занимают все разряды мантиссы, 2) уже сами по себе представляются неточно (с округлением до младшего разряда мантиссы), 3) могут давать "переполнение мантиссы" уже при первом же сложении\умножении. Поэтому, несмотря на то, что для вещественных чисел в x87 предусмотрена генерация исключения Inexact-Result в случае любого неточного представления мантиссы, на практике этим практически не пользуются - если только в каких-то особых случаях, типа твоих "экспериментальных исследований" ![]() |
Сообщ.
#48
,
|
|
|
Цитата Eric-S @ Хорошее описание, хотя формат неплохо описан и википедии, в русской описаны двоичные форматы, в английской кроме этого есть описания двоично-кодированных десятичных, да и вообще там подробнее. И ещё ссылочку. |
Сообщ.
#49
,
|
|
|
Цитата amk @ Хорошее описание На википедии есть. Я же от туда и ссылочку взял. Но мне понравилась живость и понятность описания. Тем более на русском. А может быть, она стала уже понятной, после нашего общения, в сей теме. В прочем, нашлось и кое-что новенькое. |