Произойдет ли произведение двух целых чисел без потерь, если оно попадет в диапазон без потерь типа с плавающей запятой? - PullRequest
3 голосов
/ 15 января 2020

Одинарная точность и Двойная точность IEEE 754 Base 2 Значения с плавающей запятой могут представлять диапазон целых чисел без потерь.

Для данного продукта A = BC, где B и C - целые числа, представленные без потерь в виде значений с плавающей запятой, это произведение A всегда без потерь, если оно математически попадает в диапазон без потерь с плавающей запятой тип?

В частности, знаем ли мы, будут ли обычные современные процессоры обеспечивать расчет продуктов таким образом, чтобы целочисленные продукты вели себя так, как описано выше?

РЕДАКТИРОВАТЬ: Для уточнения по ссылкам выше диапазонов целых чисел, которые можно представить без потерь, это + -2 53 в Double Precision и + -16777216 в одинарной точности.

РЕДАКТИРОВАТЬ: IEEE-754 требует, чтобы операции были округлены до максимально представительной точности, но я специально хочу узнать о поведении современных процессоров

1 Ответ

5 голосов
/ 15 января 2020

Для любой элементарной операции IEEE-754 требует, чтобы, если математический результат представим, то это был результат.

Вопрос не помечен IEEE-754 и поэтому просто спрашивает о плавающей точке в общем. Ни одна разумная система не дала бы неточных результатов, когда точные результаты представимы, но тем не менее было бы возможно создать их.

Дополнение

Вот программа для проверки float случаев.

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


static void Test(float x, float y, float z)
{
    float o = x*y;
    if (o == z) return;

    printf("Error, %.99g * %.99g != %.99g.\n", x, y, z);
    exit(EXIT_FAILURE);
}


static void TestSigns(float x, float y, float z)
{
    Test(-x, -y, +z);
    Test(-x, +y, -z);
    Test(+x, -y, -z);
    Test(+x, +y, +z);
}


int main(void)
{
    static const int32_t SignificandBits = 24;
    static const int32_t Bound = 1 << SignificandBits;

    //  Test all x * y where x or y is zero.
    TestSigns(0, 0, 0);
    for (int32_t y = 1; y <= Bound; ++y)
    {
        TestSigns(0, y, 0);
        TestSigns(y, 0, 0);
    }

    /*  Iterate x through all non-zero significands but right-adjusted instead
        of left-adjusted (hence making the low bit set, so the odd numbers).
    */
    for (int32_t x = 1; x <= Bound; x += 2)
    {
        /*  Iterate y through all non-zero significands such that x * y is
            representable.  Observe that since x and y each have their low bits
            set, x * y has its low bit set.  Then, if Bound <= x * y, there is
            a also bit set outside the representable significand, so the
            product is not representable.
        */
        for (int32_t y = 1; (int64_t) x * y < Bound; y += 2)
        {
            /*  Test all pairs of numbers with these significands, but varying
                exponents, as long as they are in bounds.
            */
            for (int xs = x; xs <= Bound; xs *= 2)
            for (int ys = y; ys <= Bound; ys *= 2)
                TestSigns(xs, ys, (int64_t) xs * ys);
        }
    }
}
...