#c_sharp #python #float #ieee_754 #floating_point
Есть стандарт IEEE 754 двоичного представления чисел и их арифметики. В нем описываются нормализованные числа и ненормализованные. В теории все понятно. Но я хочу на консоль распечатать несколько ненормализованных чисел в их внутреннем представлении, машинном, т.е. с характеристикой и мантиссой. Как это можно сделать, например, на Python, C#? И еще попутно вопрос. Можно ли работать в языках высокого уровня с вещественными литералами в двоичной системе счисления?
Ответы
Ответ 1
Но я хочу на консоль распечатать несколько ненормализованных чисел в их внутреннем представлении, машинном, т.е. с характеристикой и мантиссой На Python3 на основе ответа с EnSO: import struct def binary(num): bins = tuple(bit for byte in (tuple(bin(c).replace('0b', '').rjust(8, '0'))\ for c in struct.pack('!f', num)) for bit in byte) print(bins[0] + ' ' + ''.join(bins[1:9]) + ' ' + ''.join(bins[9:])) binary(1.0) binary(-1.0) binary(1.175494351e-38) binary(1.401298464e-45) Отдельно выводятся знак, порядок (смещённый) и мантисса. Для чисел двойной точности нужно заменить !f на !d и соответственно выводить больше байт для порядка: import struct def binary(num): bins = tuple(bit for byte in (tuple(bin(c).replace('0b', '').rjust(8, '0'))\ for c in struct.pack('!d', num)) for bit in byte) print(bins[0] + ' ' + ''.join(bins[1:12]) + ' ' + ''.join(bins[12:])) binary(2.716154612436e-312) Чтобы перевести биты обратно в число, можно использовать такую функцию: def binary_to_float(num): return struct.unpack("!f", int(num, 2).to_bytes(4, byteorder='big'))[0] print(binary_to_float('10111111100000000000000000000000'))Ответ 2
В Питоне, можно float.hex метод использовать, чтобы точное представление числа с плавающей точкой напечатать (как %a в Си (C99): [-]0xh.hhhp±d): >>> 2.716154612436e-312 .hex() '0x0.0008000000000p-1022' Если хочется байты увидеть представления IEEE 754 binary64: >>> import struct >>> data = struct.pack('d', 2.716154612436e-312) >>> data b'\x00\x00\x00\x00\x80\x00\x00\x00' В виде бит это выглядит как: >>> import sys >>> bits = bin(int.from_bytes(data, sys.byteorder))[2:].zfill(64) >>> bits '0000000000000000000000001000000000000000000000000000000000000000' Так как порядок 0, то дано денормализованное число: >>> bits[0] # знаковый бит '0' # -> положительное число >>> bits[1:12] # порядок (exponent) '00000000000' Денормализованные числа вычисляются по формуле: ±знак × (0+мантисса/ 252) · 21 − 1023 (double): >>> significand = int(bits[13:], 2) >>> hex(significand) '0x8000000000' >>> significand / 2**52 * 2**-1022 2.716154612436e-312 И в обратную сторону: >>> 2.716154612436e-312 .as_integer_ratio() (1, 368167554019802297902961703073592265444961685287384386095984806211036520049665972495786961556290633771253993225976613596485201446531925242865351537949643006725668645734124513845866945743352000756639913885870091814580532597437363981258574050387614181710541845882032738795411959682006458992302809763070411033018368) >>> _[0] / _[1] 2.716154612436e-312 Чтобы получить представление как: f = m * 2**e, можно math.frexp() вызывать: >>> import math >>> math.frexp(2.716154612436e-312) (0.5, -1034) >>> (1/2) * 2**-1034 2.716154612436e-312 Чтобы в двоичной системе дробное представление числа с плавающей точкой получить: >>> float_to_bin(2.716154612436e-312) '0b0.0000000000001000000000000000000000000000000000000000p-1022' См. Преобразование дробного числа к двоичной системе счисления.
Комментариев нет:
Отправить комментарий