Как найти длину мантиссы на конкретном станке?
-
20-08-2019 - |
Вопрос
Я хочу найти количество цифр мантиссы и округление единицы измерения на конкретном компьютере.У меня есть представление о том, что это такое, просто я понятия не имею, как их найти - хотя я понимаю, что они могут варьироваться от компьютера к компьютеру.
Мне нужно это число для того, чтобы выполнить определенные аспекты численного анализа, например, проанализировать ошибки.
В настоящее время я думаю о том, что я мог бы написать небольшую программу на c ++ для медленного увеличения числа до тех пор, пока не произойдет переполнение, но я не уверен, какой тип числа использовать.
Нахожусь ли я на правильном пути?Как именно можно это рассчитать?
Решение
Я бы подумал, что какой бы язык вы ни использовали, он указывал бы, как хранятся значения с плавающей точкой.Я знаю, что Java делает это с помощью определенного стандарта IEEE (754, я думаю).
Если это не указано, я бы подумал, что вы могли бы просто выполнить свою собственную проверку, добавив 0,5 к 1, чтобы увидеть, изменится ли фактическое число.Если это так, то добавьте 0,25 к 1, 0,125 к 1 и так далее, пока число не изменится, что-то вроде:
float a = 1;
float b = 0.5;
int bits = 0;
while (a + b != a) {
bits = bits + 1;
b = b / 2;
}
Если бы у вас было только 3 бита мантиссы, то 1 + 1/16 было бы равно 1.
Тогда вы исчерпали свои кусочки мантиссы.
Возможно, вам действительно нужно, чтобы базовое число было 2, а не 1, поскольку IEEE754 использует подразумеваемое '1 +' в начале.
Редактировать:
Похоже, что описанный выше метод может иметь некоторые проблемы, поскольку он выдает 63 бита для системы, которая явно имеет 4-байтовые значения с плавающей запятой.
Связано ли это с промежуточными результатами (я сомневаюсь в этом, поскольку тот же код с явными приведениями [while (((float)(a + b) != (float)(a))
] имеет аналогичные проблемы) или (что более вероятно, я полагаю) возможность того, что единичное значение a
может быть представлен битами, более близкими к дробному b
регулируя показатель степени, я пока не знаю.
На данный момент лучше всего полагаться на информацию о языке, которую я упомянул выше, такую как использование IEEE754 (если эта информация доступна).
Я оставлю проблемный код в качестве ловушки для осторожных игроков.Может быть, у кого-то больше знаний о плавающей запятой, тогда я смогу оставить записку, объясняющую, почему это действует странно (никаких предположений, пожалуйста:-).
ПРАВКА 2:
Этот фрагмент кода исправляет это, гарантируя, что промежуточные элементы хранятся в floats .Оказывается, Джонатан Леффлер был прав - это были промежуточные результаты.
#include <stdio.h>
#include <float.h>
int main(void) {
float a = 1;
float b = 0.5;
float c = a + b;
int bits = 1;
while (c != a) {
bits = bits + 1;
b = b / 2;
c = a + b;
}
printf("%d\n",FLT_MANT_DIG);
printf("%d\n",bits);
return 0;
}
Этот код выводит (24,24), чтобы показать, что вычисленное значение соответствует значению в заголовочном файле.
Хотя он написан на C, он должен быть применим к любому языку (в частности, к тому, где информация недоступна в заголовке или в силу того, что она указана в языковой документации).Я тестировал только на C, потому что Eclipse так долго запускается на моем компьютере Ubuntu :-).
Другие советы
Для C и, расширяя C ++, информация находится в <float.h>
или <cfloat>
заголовки.
Для C99 информация приведена в разделе 5.2.4.2.2 стандарта:
FLT_RADIX
FLT_MANT_DIG
FLT_DIG
FLT_EPSILON
FLT_MIN_EXP
FLT_MIN
FLT_MIN_10_EXP
FLT_MAX_EXP
FLT_MAX
FLT_MAX_10_EXP
И аналогично для вариаций DBL и LDBL для большинства из них (нет DBL_RADIX
или LDBL_RADIX
).Стандарт предлагает значения, соответствующие стандарту IEEE 754 (более старая версия стандарта IEEE 754 , действовавшая в 1999 году;была новая версия, опубликованная, по-моему, в 2008 году).
Возможно, вы захотите проверить <limits>
в вашей библиотеке C ++:
#include <iostream>
#include <limits>
#include <typeinfo>
template <typename T>
void printDetailsFor() {
std::cout
<< "Printing details for " << typeid(T).name() << ":\n"
<< "\tradix: " << std::numeric_limits<T>::radix << "\n"
<< "\tradix digits: " << std::numeric_limits<T>::digits << "\n"
<< "\tepsilon: " << std::numeric_limits<T>::epsilon() << "\n"
<< std::endl;
}
int main() {
printDetailsFor<int>();
printDetailsFor<float>();
printDetailsFor<double>();
printDetailsFor<long double>();
return 0;
}
Я думаю, что ты хочешь std::numeric_limits<T>::digits
что должно быть на единицу больше, чем количество битов мантиссы.Моя машина распечатывает:
Printing details for i:
radix: 2
radix digits: 31
epsilon: 0
Printing details for f:
radix: 2
radix digits: 24
epsilon: 1.19209e-07
Printing details for d:
radix: 2
radix digits: 53
epsilon: 2.22045e-16
Printing details for e:
radix: 2
radix digits: 64
epsilon: 1.0842e-19