Преобразование дважды для плавания, не полагаясь на режим округления FPU

Делает любой имеет удобный отрывки кода для преобразования IEEE 754 double к сразу нижнему (resp. выше) float, не изменяясь или принимая что-нибудь о текущем режиме округления FPU?

Примечание: это ограничение, вероятно, подразумевает не использование FPU вообще. Я ожидаю, что самый простой способ сделать это в этих условиях состоит в том, чтобы считать биты двойного в 64-разрядном длинном и работать с этим.

Можно принять порядок байтов по Вашему выбору для простоты, и что двойное рассматриваемое доступно через d поле объединения ниже:

union double_bits
{
  long i;
  double d;
};

Я попытался бы сделать это сам, но я уверен, что представил бы трудные к уведомлению ошибки для денормализованных или отрицательных чисел.

5
задан mskfisher 9 May 2012 в 19:19
поделиться

2 ответа

думаю, что это сработает, но сначала я сформулирую свои предположения:

  • числа с плавающей точкой на вашей реализации хранятся в формате IEEE-754,
  • Переполнения нет,
  • У вас есть nextafterf() (он указан в C99).

Также, скорее всего, этот метод не очень эффективен.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
    /* Change to non-zero for superior, otherwise inferior */
    int superior = 0;

    /* double value to convert */
    double d = 0.1;

    float f;
    double tmp = d;

    if (argc > 1)
        d = strtod(argv[1], NULL);

    /* First, get an approximation of the double value */
    f = d;

    /* Now, convert that back to double */
    tmp = f;

    /* Print the numbers. %a is C99 */
    printf("Double: %.20f (%a)\n", d, d);
    printf("Float: %.20f (%a)\n", f, f);
    printf("tmp: %.20f (%a)\n", tmp, tmp);

    if (superior) {
        /* If we wanted superior, and got a smaller value,
           get the next value */
        if (tmp < d)
            f = nextafterf(f, INFINITY);
    } else {
        if (tmp > d)
            f = nextafterf(f, -INFINITY);
    }
    printf("converted: %.20f (%a)\n", f, f);

    return 0;
}

На моем компьютере он печатает:

Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)

Идея заключается в том, что я преобразую значение double в float - оно может быть меньше или больше двойного значения в зависимости от режима округления. При преобразовании обратно в double мы можем проверить, меньше или больше ли оно исходного значения. Затем, если значение float не в правильном направлении, мы посмотрим на следующее float число из преобразованного числа в направлении исходного числа.

.
3
ответ дан 14 December 2019 в 04:39
поделиться

Чтобы сделать эту работу точнее, чем просто перекомбинировать мантиссу и бит экспонента, проверьте:

http://www.mathworks.com/matlabcentral/fileexchange/23173

regards

.
3
ответ дан 14 December 2019 в 04:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: