6

Я нашел Stevens Computing Services – K & R Exercise 2-1 очень тщательный ответ K & R 2-1. Этот фрагмент полного кода вычисляет максимальное значение типа float на языке программирования C.Вычисление точности с плавающей запятой (K & R 2-1)

К несчастью мое теоретическое понимание значений float весьма ограничено. Я знаю, что они состоят из мантиссы (мантисса ..) и величина, которая является степенью 2.

#include <stdio.h> 
#include <limits.h> 
#include <float.h> 

main() 
{ 
    float flt_a, flt_b, flt_c, flt_r; 

    /* FLOAT */ 
    printf("\nFLOAT MAX\n"); 
    printf("<limits.h> %E ", FLT_MAX); 

    flt_a = 2.0; 
    flt_b = 1.0; 
    while (flt_a != flt_b) { 
     flt_m = flt_b;   /* MAX POWER OF 2 IN MANTISSA */  
     flt_a = flt_b = flt_b * 2.0; 
     flt_a = flt_a + 1.0; 
    } 
    flt_m = flt_m + (flt_m - 1); /* MAX VALUE OF MANTISSA */ 

    flt_a = flt_b = flt_c = flt_m; 
    while (flt_b == flt_c) { 
     flt_c = flt_a;   
     flt_a = flt_a * 2.0; 
     flt_b = flt_a/2.0; 
    } 
    printf("COMPUTED %E\n", flt_c); 
} 

Я понимаю, что последняя часть в основном проверяет, к которому мощность 2, что можно поднять мантиссу с микросхемой три переменных алгоритма. Как насчет первой части?

Я вижу, что прогрессирование кратных 2 должно в конечном итоге определять значение значащего, но я попытался проследить несколько небольших чисел, чтобы проверить, как он должен работать, и ему не удалось найти правильные значения ...

============================================================================================================================================== ==================================

Каковы концепции, на которых основана эта программа, и эта программа становится более точной, целочисленные числа должны быть найдены?

+0

@TonyK, вычисление 'flt_m' идеально подходит. Он вычисляет один меньше, чем дважды 'flt_m', с осторожностью, чтобы избежать потери точности. И нет ничего плохого в стиле, учитывая, что он написан в K & R C. –

+0

@JohnBollinger С осторожностью, чтобы избежать потери точности. Абсолютно нет, 'flt_m + flt_m - 1' будет ближайшим поплавком до 2 *' flt_m' - 1 для всех значений 'flt_m'. Вместо этого назначение записывается таким образом, чтобы быть самодокументированным («MAX VALUE OF MANTISSA»). –

+0

@PascalCuoq, я полагаю, мы оба размышляем. Тем не менее, я нахожу конструкцию ничего *, но * самодокументирую. Единственная причина для меня, которая имеет для меня смысл, - избегать любого промежуточного результата (например, 2 * 'flt_m'), который хуже, чем единичная точность. Правдоподобно, что, имея такое значение как один вход, сумматор может преобразовать другой в тот же масштаб, прежде чем вычислять их сумму. Реализация, которая сделала это (без повышения точности), могла бы вычислить результат, отличный от желаемого. –

ответ

3

Первый цикл определяет количество бит, способствующих значению, путем поиска наименьшей мощности 2, так что добавление 1 к нему (с использованием арифметики с плавающей запятой) не может изменить его значение. Если это n-я степень двух, то значение использует n бит, потому что с n битами вы можете выразить все целые числа от 0 до 2^n - 1, но не 2^n. Поэтому представление с плавающей запятой 2^n должно иметь показатель, достаточно большой, чтобы (двоичная) единица измерения была незначительной.

К тому же, обнаружив первую степень 2, чье float представление имеет хуже, чем единицы точности, то maximim float значение, которое делает иметь блок точность на один меньше. Значение указано в переменной flt_m.

Второй цикл затем проверяет максимальную экспоненту, начиная с максимального значения единицы измерения и повторяя удвоение его (тем самым увеличивая показатель на 1), пока не найдет, что результат не может быть преобразован обратно, уменьшив его вдвое. Максимальное значение float - это значение перед этим окончательным удвоением.

Обратите внимание, что все вышеперечисленное допускает представление с плавающей запятой base-2. Вы вряд ли столкнетесь с чем-то другим, но C фактически не требуют любого конкретного представления.

Что касается второй части вашего вопроса,

делает эта программа становится все более точным, как больше и не целые числа, которые можно найти?

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

+0

Значение 'FLT_EVAL_METHOD' может иметь значение 1 или 2, все операции' float' выполняются с помощью метода 'double' или' long double' precision/range failing OP. – chux

+0

@chux, даже если вычисления выполняются с большей точностью, что более высокая точность теряется, когда результат присваивается переменной типа 'float'. Реализации должны вести себя так, как если бы это произошло, даже если они оптимизировали некоторые из фактических заданий. –

+0

C11 §5.2.4.2.2 9 «За исключением назначения и литья (которые удаляют весь дополнительный диапазон и точность), ...» поддерживает вашу проницательную коррекцию. – chux

Смежные вопросы