Англомовная: http://board.flatassembler.net/topic.php?t=11847 Полный архив: http://code.google.com/p/fasmme/downloads/detail?name=80%20bit%20floats.rar&can=2&q= Надеюсь где-то поможет. Сам учил с мая 2009, было трудно. Код (Text): _________________________________________________________ 80 bit floats - числа с плавающей запятой размером 80 бит Этот документ ни коим образом не претендует на звание путеволителя по форматам чисел. На то есть специализированные справочники, перепечатывать которые нету смысла. Все же мы постараемся пролить некий свет на целевой тип данных, с которыми оперирует FPU(сопроцессор). И так, 80 бит = десять байт = TBYTE. Именно их и рассмотрим, так как те наиболее длинные и позволяют, соответственно, разширить диапазон всевозможных значений. Любые данные на стадии загрузки автоматически переводятся именно в такую форму. Как совет, всегда ищите сходимости/аналогии между тем, что вы знаете и чего нет. Пускай в нас есть 625d чего-то. Разложим: 6*10^2 + 2*10^1 + 5*10^0 = = 600 + 20 + 5 = = 625 = = 6.25e2 А чего-то есть ровно столько 0.625d. Так, для разминки: 0*10^0 + 6*10^-1 + 2*10^-2 + 5*10^-3 = = 0 + 0.6 + 0.02 + 0.005 = = 0.625 = = 6.25e-1 Посмотрим, как целое 625d смотрится в двойке: 625 / 2, 1 -> Проверим: 1*2^0 = 001 + 312 / 2, 0 -> + 0*2^1 = 000 + 156 / 2, 0 -> + 0*2^2 = 000 + 078 / 2, 0 -> + 0*2^3 = 000 + 039 / 2, 1 -> остатки + 1*2^4 = 016 + 019 / 2, 1 -> + 1*2^5 = 032 + 009 / 2, 1 -> + 1*2^6 = 064 + 004 / 2, 0 -> + 0*2^7 = 000 + 002 / 2, 0 -> + 0*2^8 = 000 + 001 / 2, 1 -> + 1*2^9 = 512 = 625 В случае нападения трудностей, делите 625 на 10, но переносите свойства на двоичную с-му исчисления - делите на 2: 625., для получения 5 мы делим на 10 для получения 2 мы делим на 10 на 10 для получения 6 мы делим на 10 на 10 на 10 Ну как, нок-аут, забили страх? = 1001110001.b * 2^0 = 100111000.1b * 2^1 = 10011100.01b * 2^2 = 1001110.001b * 2^3 = 100111.0001b * 2^4 = 10011.10001b * 2^5 = 1001.110001b * 2^6 = 100.1110001b * 2^7 = 10.01110001b * 2^8 = 1.001110001b * 2^9, fpu всегда старается представлять числа именно так - это нормализация Ура, мы знаем способ получения целой части :)% Так идемте за щебнем, 625.625d, о я о дробовой части, пардон: 625, уже известно, равно 1001110001b и, словно в десятичной, в двоичной тоже остается присоединить дробь 0.625. Возвратимся к нашей нумерике: 0.625, для получения 6 умножаем на 10 для получения 2 умножаем на 10 еще на 10 для получения 5 умножаем на 10 еще на 10 и еще на 10 только для бинарного счисления множим на 2: 0.625 * 2, 1 -> Сверимся: 1*2^-1 = 0.500 + 0.250 * 2, 0 -> остатки + 0*2^-2 = 0.000 + 0.500 * 2, 1 -> + 1*2^-3 = 0.125 = 0.625 = 0.101b * 2^0 = 1.010b * 2^-1, fpu всегда старается представлять числа именно так - это нормализация, а числа зовут нормализированными, но не мучайте этим голову просто следуем традиции Совмещаем 625.0 и 0.625. Во-первых, упорядочим суммируемые, так как 625.0 + 0.625 неверно. 625.0 + 0.625 = 625.625 верно. FPU тоже так делает(ясный день/пень/картошка), тем самым теряя драгоценную дробь, биты, хвост, остаток, звите как хотите. Именно поэтому 80 бит - целевой формат, хотя те тоже не бесконечны. 1001110001.000b + 0.101b = 1001110001.101b * 2^0 = 1.001110001101b * 2^9 положительн---отрицательные степени двух Вроде так, давайте намуляем мозоль. Как знаете, ЧИСЛО/10=ЧИСЛО*0.1. Че, поехали :? 0.1 * 2 ------- 0.2 * 2 0.4 * 2 0.8 * 2 ....... 1.6 * 2 1.2 * 2 0.4 * 2 0.8 * 2 ....... 1.6 * 2 .000(1100)b, вы догадались что это? Примерно = .0001101b, если заокруглить. Видели, 0.1 - нескончаемая дробь. Располагая на DWORD: .1100'1100'1100'1100'1100'1100'1100'1101 двоично shr 3 = .c c c c c c c d 16тирично shr 3 Учтите простой принцип: 10*0.1 = 10*1.0/10. Отсюда, для выделения целой части, нужно выполнить eax*edx shr 32+3. 32 из-за того, что .cccc'cccd CPU рассматривает, как обычное целое. Вспоминаем принцип выше! 03 из-за того, что .cccc'cccd = 0.1 * shl 3 те умноженное на три для нормализации. [код] mov edx,$cccccccd ;0.1 * 2^+3 mov eax,1'234'567'890 ;делимое, любое число, даже 0 mul edx ;ЧИСЛО*0.1, получим 64 бит: DWORD*DWORD=QWORD shr edx,3 ;целое есть [/код] Обошлись без О-всемогучего FpU, кста не правда о могучести. В будущем, возможно, сопроцессор вам сослужит в кошелек или в уважуху, так распишем TBYTE, а то трандосим. Зато в тему: 0'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b | | | | | |мантиса размером в 64 бит | | | |2-кова степень или экспонента(15 бит ее размер), умножаемая на мантису | |знак числа размером в бит, 1="-", 0="+" +0d = 0'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b -0d = 1'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b В западло десяти, степень двух(экспонента) подкручивает счетчик своего рейтинга - и 0 = $3fff. Следовательно -1=$3fff-1, 1=$3fff+1, и тд. Также: FXTRACT в исполнении FPU и ему подобных, выковыривая мантису в ST0 и экспоненту в ST1, ведут себя вот так неадекватно: $0000'8xxxxxxx'xxxxxxxx -> -16'382 $0000'4xxxxxxx'xxxxxxxx -> -16'383 обратите внимание, чему равна экспонента Эх, вот они: +625.625 = 0'100000000001000'1.001110001101000000000000000000000000000000000000000000000000000b -625.625 = 1'100000000001000'1.001110001101000000000000000000000000000000000000000000000000000b _______________ -----____----____ $3fff+9=4008 9 c 6 8 Чутка практики. Суммируем: 625.625 + 001.000 = 626.625 разнормализируем 625.625, ссовывая число 9 раз влево, тоесть получем реальное число 1001110001.101000000000000000000000000000000000000000000000000000b разнормализируем 001.000, ссовывая 0 раз ни влево, ни вправо 1.000000000000000000000000000000000000000000000000000000000000000b суммируем, вспомните, как додавали 625. и .625 1001110010.101000000000000000000000000000000000000000000000000000b нормализируем 1.001110010101000000000000000000000000000000000000000000000000000b hex $4008'9ca80000'00000000 Суммируем: 625.625 + 625.625 = 1251.25 выровнять/разнормализировать оба числа за позициями комм и сложить 1001110001.101000000000000000000000000000000000000000000000000000b 1001110001.101000000000000000000000000000000000000000000000000000b 10011100011.01000000000000000000000000000000000000000000000000000b нормализируем, подтягивая точку/комму вверх на 10 позиций помните о балансировании: на сколько множим - на столько и делим, и наоборот, на то она и экспонента 1.001110001101000000000000000000000000000000000000000000000000000b hex $4009'9c680000'00000000 Суммируем: 625.000 - 625.625 = -(625.625-625.000) = -0.625 мантисы вравновешены, нечего двигать, отнимаем 1.001110001101000000000000000000000000000000000000000000000000000b 1.001110001000000000000000000000000000000000000000000000000000000b 0.000000000101000000000000000000000000000000000000000000000000000b нормализируем умножением на 2^10(сдвигом 10 позиций влево) 1.010000000000000000000000000000000000000000000000000000000000000b hex $3fff+9-10'a0000000'00000000 МЕНШЕ 0 $3ffe 'a0000000'00000000 МЕНШЕ 0 $bffe 'aaaaaaaa'00000000 Множим: a^x * a^y = a^(x+y) напр. 1.5*0.75 = 15*10^-1 * 75*10^-2 = 15*75*10^(-1+-2) для понимания помучаем CPU 1.50 = 3FFF'C0000000'00000000 = 2^0 * 1.1b 0.75 = 3FFE'C0000000'00000000 = 2^-1 * 1.1b заново просмотрите деление на десять ... заново просмотрите умножение на 0.1 ... хохе, вы уяснили, да нет, не "не на *беш - не проживешь", как умножать дошло :? кстати, поговорка паршивая, никогда не дурите людей повторимся о маневрах: 0.1*0.1 = 1*1/10/10 [код] mov eax,$C0000000 mov edx,$C0000000 mul edx shrd eax,edx,31*2+1-32 shr edx,31*2+1-32 ;edx.eax = целое.дробь = 1.125 ;результат, как целое. в edx, может стать разнормализированным ;дробь в EAX=$20000000 тоже ;та ну и пусть, главное, чтоб осмысливали процесс [/код] Множим: 00.9 = 3FFE'E6666666'66666666, exp=-1 10.0 = 4002'A0000000'00000000, exp=+3 [код] mov eax,$E6666667 mov edx,$a0000000 mul edx shr edx,31*2+1-3-32 ;edx=9 [/код] Будет время, сходите сюда: http://ray.masmcode.com/ http://www.intel.com/products/processor/manuals/ Писалось: 2010_08_28, 10:52, время было киевское 2010_08_28, 23:00, русская версия Меня вы знаете: edemko@rambler.ru
Интересное форматирование получилось, писал в wink.exe(прототип fasmw.exe). Возможно это форум или опция фасма "Optimal fill on saving". В редакторе смотрелось ок.
- Эт, вряд ли - усмехнулся Сухов (C) Особенно интересен стиль изложения, расчитанный на разные целевые аудитории - одним "где суть", а другим - "где захотят, там и суть", а в итоге - "за двумя зайцами погонишься - ни одного не поймаешь"
[leo] Переводясь на физ-мат, я осозновал объемы академок, их было 10. Пытался до горечи учить умные книги. Прошол год, академки так и висели, а успехи те же. Меня отчислили. Восстановился, за 4 месяца сдал 9 штук + 2 хвоста, с сентября могут взять на госзаказ. Никаких взяток не давал. Так чего же такого начитался? Вы все правильно сказали. [/leo] Поделитесь примером деления tbyte.
Зачем ?! Для этого есть сопроцессор, он же FPU. А если его где-то нет, то и нефиг связываться с tbyte и вообще с плавяющей точкой - достаточно fixed
edemko Могу сбросить исходники библиотеки floating-point для AVR. Там, правда, только 64 бита, но мало не покажется
leo, может я не прав, но мне хотелось добавить смысла в: http://user.cs.tu-berlin.de/~lordmaik/projects/IEEE754Converter/ieee754.htm http://user.cs.tu-berlin.de/~lordmaik/projects/IEEE754Converter/FloatingPointArithmeticsIEEE754Examples.pdf Ustus, ок
edemko Э-э-э... вообще-то это была шутка. Но если надо - могу скинуть, только аккуратно, ибо варез. Уточняю еще раз. Библиотека для AVR. Atmel. RISC8. На асме Точно надо?