Как узнать длину мантиссы на конкретной машине? - PullRequest
3 голосов
/ 02 февраля 2009

Я хочу найти количество цифр мантиссы и округление устройства на конкретном компьютере. Я понимаю, что это такое, просто не знаю, как их найти - хотя я понимаю, что они могут варьироваться от компьютера к компьютеру.

Мне нужно это число для выполнения определенных аспектов численного анализа, таких как анализ ошибок.

Что я сейчас думаю, так это то, что я мог бы написать небольшую программу на c ++, чтобы постепенно увеличивать число, пока не произойдет переполнение, но я не уверен, какой тип числа использовать.

Я на правильном пути? Как именно можно рассчитать это?

Ответы [ 3 ]

5 голосов
/ 02 февраля 2009

Я думаю, что какой бы язык вы ни использовали, вы бы указали, как хранятся числа с плавающей запятой. Я знаю, что 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+» в начале.

EDIT:

Похоже, что описанный выше метод может иметь некоторые проблемы, так как он дает 63 бита для системы, которая явно имеет 4-байтовые числа с плавающей запятой.

Является ли это результатом промежуточных результатов (я сомневаюсь в этом, поскольку тот же код с явными приведениями [while (((float)(a + b) != (float)(a))] имеет аналогичные проблемы) или (более вероятно, я полагаю) вероятность того, что значение единицы a можно представить с битами ближе к дробному b путем корректировки показателя степени, я пока не знаю.

На данный момент лучше полагаться на информацию о языке, которую я упомянул выше, например, на использование IEEE754 (если такая информация имеется).

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

РЕДАКТИРОВАТЬ 2:

Этот фрагмент кода исправляет это, гарантируя, что промежуточные продукты хранятся в числах с плавающей точкой. Оказывается, Джонатан Леффлер был прав - это были промежуточные результаты.

#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 box: -).

1 голос
/ 02 февраля 2009

Возможно, вы захотите проверить <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
1 голос
/ 02 февраля 2009

Для 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 году была опубликована новая версия).

...