Округлить x с плавающей точкой до y с уменьшенной (существенной) мантиссой - PullRequest
0 голосов
/ 10 января 2019

Я хотел бы понять, как округлить, например, IEEE float32 с 23 битами с уменьшенной мантиссой единицей (т. Е. 20,19). Желательно пошаговое решение на Python.

1 Ответ

0 голосов
/ 10 января 2019

Вот ответ, использующий только базовый Python и стандартный math модуль.

from math import frexp, ldexp

def roundbits(fval, nbits):
    """Return the floating-point value `fval` rounded to `nbits` bits
    in the significand."""
    significand, exponent = frexp(fval)
    scale = 2.0 ** nbits
    newsignificand = round(significand * scale) / scale
    return ldexp(newsignificand, exponent)

Вот объяснение. Чтобы округлить значение до nbits битов в значении и его представлении с плавающей запятой, сначала получите биты значимого и масштабируйте их так, чтобы наиболее значимый бит приходился сразу после радикальной точки, а затем следуют другие биты. Это то, что делает функция frexp. Затем, умножьте это значениеи на 2**nbits, что ставит количество битов, которые мы хотим, до точки радиуса и нежелательные биты после точки радиуса. (И это значение масштаба, и умножение будут выполнены точно, для разумных значений nbits.) Затем мы округляем это значение до ближайшего целого числа, которое удаляет ненужные биты. Затем разделите это значение обратно на 2**nbits, что сдвинет самый значимый бит обратно сразу после точки радиуса. Наконец, используйте новое значение и старый показатель для создания числа с плавающей запятой - это то, что делает функция ldexp.

Эта процедура была простой, поэтому она игнорирует некоторые крайние случаи. Что если число желаемых битов отрицательно или равно нулю или больше, чем Python может хранить в своих значениях с плавающей запятой? Python обычно использует двойной тип, который использует 64 бита для всего числа с плавающей запятой и 53 бита (52 явно хранятся) в значении, но это не гарантируется. Я оставлю вам проверку ошибок.

Если вы тестируете эту процедуру с

for n in range(1, 52):
    print(n, roundbits(pi, n))

, который использует pi, который находится в двоичном формате до 53 бит,

11.00100100001111110110101010001000100001011010001100001000110100

результат

1 4.0
2 3.0
3 3.0
4 3.25
5 3.125
6 3.125
7 3.15625
8 3.140625
9 3.140625
10 3.140625
11 3.140625
12 3.1416015625
13 3.1416015625
14 3.1416015625
15 3.1416015625
16 3.1416015625
17 3.1416015625
18 3.1415863037109375
19 3.1415939331054688
20 3.1415939331054688
21 3.141592025756836
22 3.1415929794311523
23 3.141592502593994
24 3.1415927410125732
25 3.1415926218032837
26 3.1415926814079285
27 3.141592651605606
28 3.141592651605606
29 3.141592651605606
30 3.1415926553308964
31 3.1415926534682512
32 3.1415926534682512
33 3.1415926534682512
34 3.141592653701082
35 3.1415926535846666
36 3.1415926535846666
37 3.1415926535846666
38 3.1415926535846666
39 3.1415926535919425
40 3.1415926535883045
41 3.1415926535901235
42 3.1415926535901235
43 3.1415926535896688
44 3.141592653589896
45 3.1415926535897825
46 3.1415926535897825
47 3.1415926535897825
48 3.1415926535897967
49 3.1415926535897967
50 3.141592653589793
51 3.141592653589793
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...