Что нового

Задача по кодировке а ля IEEE 754

dwerf

Использует ArchLinux
Сообщения
478
Репутация
218
Дано:
16 бит для хранения числел с плаващей запятой
относительная точность не должна падать ниже 0,1%

Необходимо найти максимальное и минимальное числа, которые влезут в эти 16 бит.

Как это чудо решить объясните пожалуйста.
 
Автор
D

dwerf

Использует ArchLinux
Сообщения
478
Репутация
218
Как решить мне оттуда к сожалению не ясно. Важен не результат, а именно решение.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
в английском варианте лучше расписано
Half precision floating-point format
там сам алгоритм тоже приведен. если не разберешься, то через пару часиков накатаю, как со всеми делами разберусь.
если вкратце, то надо перевести hex в bin. потом парсить его биты. там каждая группа битов за что-то отвечает. я такое уже делал правда для single и double
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
я чесгря так и не понял, что надо. само кодирование, или только максимум и минимум? если кодирование, то код ниже, но говорю сразу. проверял на питоне, и потом по памяти переводил на AutoIt. могут быть ошибки. Самого AutoIt под рукой нет, проверить возможности тоже нет. Для надежности привожу код и на питоне, он рабочий.
Код:
Func _HexToBin($sHex)
     $sBin = ''
     $aHex = StringSplit($sHex, '', 2)
     For $xDig in $aHex
     	 $sBin &= _DigToBin($xDig)
     Next
     Return $sBin
EndFunc

Func _DigToBin($xDig)
     Switch $xDig
     	    Case '0'
	    	 Return '0000'
     	    Case '1'
	    	 Return '0001'	    	 
     	    Case '2'
	    	 Return '0010'
     	    Case '3'
	    	 Return '0011'
     	    Case '4'
	    	 Return '0100'
     	    Case '5'
	    	 Return '0101'
     	    Case '6'
	    	 Return '0110'
     	    Case '7'
	    	 Return '0111'
     	    Case '8'
	    	 Return '1000'
     	    Case '9'
	    	 Return '1001'
     	    Case 'A'
	    	 Return '1010'
     	    Case 'B'
	    	 Return '1011'
      	    Case 'C'
	    	 Return '1100'
     	    Case 'D'
	    	 Return '1101'
     	    Case 'E'
	    	 Return '1110'
     	    Case 'F'
	    	 Return '1111'
     EndSwitch
EndFunc

Func _BinToInt($sBin)
     $sInt = 0
     $iLen = StringLen($sBin)
     $aBin = StringSplit($sBin, '', 2)
     For $i = 0 to $iLen - 1
     	 $iDig = Number($aBin[$i])
	 $sInt += $iDig*2^($iLen - $i - 1)
     Next
     Return $sInt
EndFunc

Func _BinToNum($sBin)
     $iLen = StringLen($sBin)
     $aBin = StringSplit($sBin, '', 2)
     $iSgn = Number($aBin[0])
     $sExp = ''
     For $i = 1 to 5
     	 $sExp &= $aBin[$i]
     Next
     $iExp = _BinToInt($sExp)
     $sRes = ''
     For $i = 6 to $iLen
     	 $sRes &= $aBin[$i]
     Next
     $iRes = _BinToInt($sRes)
     $iNum = (-1)^$iSgn*2^($iExp - 15)*(1 + $iRes)
     Return $iNum
EndFunc

Func _HexToNum($sHex)
     $sBin = _HexToBin($sHex)
     $iNum = _BinToNum($sBin)
EndFunc

$sHex1 = '7BFF' ; max number in half-precise format
$sHex2 = '0400' ; min number in hals-precise format

MsgBox(0, '', '0x7BBFF is ' & _HexToNum($sHex1) & @CRLF & '0x0400 is ' & _HexToNum($sHex2))

Код:
def _HexToBin(sHex):
    sBin = ''
    for xDig in sHex:
        sBin += _DigToBin(xDig)
    return sBin

def _DigToBin(xDig):
    if xDig == '0':
        return '0000'
    elif xDig == '1':
        return '0001'
    elif xDig == '2':
        return '0010'
    elif xDig == '3':
        return '0011'
    elif xDig == '4':
        return '0100'
    elif xDig == '5':
        return '0101'
    elif xDig == '6':
        return '0110'
    elif xDig == '7':
        return '0111'
    elif xDig == '8':
        return '1000'
    elif xDig == '9':
        return '1001'
    elif xDig == 'A':
        return '1010'
    elif xDig == 'B':
        return '1011'
    elif xDig == 'C':
        return '1100'
    elif xDig == 'D':
        return '1101'
    elif xDig == 'E':
        return '1110'
    elif xDig == 'F':
        return '1111'

def _BinToInt(sBin):
    sInt = 0
    iLen = len(sBin)
    for i in range(iLen):
        iDig = float(sBin[i])
        sInt += iDig*2**(iLen - i - 1)
    return sInt

def _BinToNum(sBin):
    iLen = len(sBin)
    iSgn = int(sBin[0])
    iExp = _BinToInt(sBin[1:6])
    iRes = _BinToInt(sBin[6:16])/(2**10)
    iNum = (-1)**iSgn*2**(iExp - 15)*(1 + iRes)
    return iNum

def _HexToNum(sHex):
    sBin = _HexToBin(sHex)
    iNum = _BinToNum(sBin)
    return iNum

sHex = '7BFF' 
sBin = '10011'
#print(_HexToBin(sHex))
#print(_BinToInt(sBin))
print(_HexToNum(sHex))
Само число половинной точности через биты соответствующего шестнадцатеричного числа выражается как
Код:
B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B8 B13 B14 B15 B16
где BN - бит.
B1 - бит знака: если 1 - то "-", если 0 то "+"
B2 - B6 - биты для вычисления экспоненты
B7 - B16 - биты для дробной части мантиссы, т.к ее целая часть почти всегда 1, 0 только если экспонента 0. (кстати код выше этого не учитывает. доработай сам для этих двух исключительных чисел. все есть на вики)
и того, если проводить анализ, то максимально число получается если экспонента и мантисса максимальна, и минимальна если наоборот. без учета вышеупомянутых двух исключительных чисел, легко найти что
Код:
NMax = 0x7BFF = 6.5E4
NMin = 0x0400 = 6.1E-5
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
апну ка я слегка тему.
dwerf
тебе хоть как-то помогли ссылки и приведенный выше код? мне просто интересно. и кстати, откуда задачка возникла?
 
Автор
D

dwerf

Использует ArchLinux
Сообщения
478
Репутация
218
К экзаменам готовился, а с этим вопросом сам не разобрался. Ну да его и не было.

Проблема в том что изначально колличество бит мантиссы и экспоненты не известно.
Их надо как то подобрать/вычислить под заданную точность.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
dwerf
почти создать новый формат ;D
даже не знаю что сказать. я в такие дебри не залезал.
 
Верх