Add Two 32 bit Floating Point Numbers with AVR-Ass

2019-12-16 19:23发布

Im trying to use AVR Studio to add two 32bit floating point numbers together. I know that I will need to store the 32bit number in 4 separate 8bit registers. I'll then need to add the registers together using the carry flag. This is what I have so far. Im adding 5.124323 and 2.2134523.

;5.124323 (01000000101000111111101001110100)
;Store hex value (40A3FA74)
ldi r21,$40
ldi r22,$A3
ldi r23,$FA
ldi r24,$74


;2.2134523 (01000000000011011010100100110100)
;Store hex value (400DA934)
ldi r25,$40
ldi r26,$0D
ldi r27,$A9
ldi r28,$34


;Add the corresponding bytes together including the carry flag
add r21,r25
adc r22,r26
adc r23,r27
adc r24,r28

This doesnt seem to give me the right answer... I'm pretty sure the only thing that's wrong here is the order of the registers in the last 4 lines of code. Or maybe the add / adc functions are also wrong. Can someone please help me out with this?

4条回答
放我归山
2楼-- · 2019-12-16 19:46

After almost 4 years you didn't receive a straight answer for the question, and you deserve it. So here we go:

You can not get Floating Point bits and simply ADD them to get the Floatting Point of the result, they are not decimal or hexadecimal numbers.

Floating Point numeric system scares a lot of people, it is a different way to represent numeric values, very useful to calculate with gigantic or microscopic numbers. We do not learn that at elementary school, not a middle school, not even at college. There is no pocket Casio calculator that can handle FP numbers, so we are not really very familiar with those, and we are all alone in the dark.

Most programmers (if not all), prefer to leave FP to be dealt by C/C++ compilers, they don't touch FP bitwise, for some it is like a plague. Anyway, FP was created by humans (the real problem), even so, there is a way to deal with it.

My intention here is not to teach you how to do it in AVR assembly, even that it is totally possible and easy, if you follow my explanations below. My intentions here is to show "the tiger" is not a monster, it is a little blue eyes petcat, but still, it is a feline with teeth and claws.

Below you will find:

1. The guts of Floating Point
2. Easy Floating Point Multiplication Easy
3. Floating Point Addition (your question)

The Guts:

The are single and double precision FP, 32 and 64 bits, lets strip the 32.

A FP number has 3 districtive areas:

Floating Point Strip

a) Sign, 1 bit, #32 (first at left), zero for positive, one for negative.
b) Exponent, 8 bits, here is where the tiger hunts, people get very confused.
c) Mantissa, 23 bits, the exponent fractions complements.

To be able to represent a very large or very small number, the center will be 1, so, when bit 7 of the Exponent (lets call it "7E") is one, the number is 1 or bigger. 7E=1 number is >=1, 7E=0 number is smaller than 1 (0.7 for example).

You don't need to count 7E as a real bit with value when thinking about the bits value of the Exponent, some people do. From now on here, we will only deal with numbers largers than 1 and positive, so I will not comment about 7E or Sign bits, nor even account it as a value of the Exponent.

The Exponent and Mantissa are binary counted. The values of the Exponent bits are the same as a regular binary number, the difference is that the bit value is always added of 1, E1=2, E2=3, E2+E1=4, E3=5... All bits E1 to E6 on = 128.

The value of the Exponent representation is 2^n, where "n" is the value of bits or combination of bits as above. The minimum will be 2^-126 a very small tinny number, and the maximum will be 2^128 a gigantic gargantuous number considered infinity, 2^127 has 39 digits.

E7.6.5.4.3.2.1.0   
 1 0 0 0 0 0 0 0 = decimal 0, but remember, it needs to add 1, so it is 1, and the value is 2^1 = 2

E7.6.5.4.3.2.1.0   
 1 0 0 0 0 0 0 1 = decimal 1, +1 = 2, 2^2 = 4   
 1 0 0 0 0 0 1 0 = decimal 2, +1 = 3, 2^3 = 8   
 1 0 0 0 0 0 1 1 = decimal 3, +1 = 4, 2^4 = 16   
 1 0 0 0 0 1 0 0 = decimal 4, +1 = 5, 2^5 = 32   
 1 0 0 0 0 1 0 1 = decimal 5, +1 = 6, 2^6 = 64   
 1 0 0 0 0 1 1 0 = decimal 6, +1 = 7, 2^7 = 128   
 1 0 0 0 0 1 1 1 = decimal 7, +1 = 8, 2^8 = 256   
 1 0 0 0 1 0 0 0 = decimal 8, +1 = 9, 2^8 = 512   
 1 0 0 1 0 0 0 0 = decimal 16, +1 = 17, 2^17 = 131072   
 1 0 0 1 0 0 0 1 = decimal 17, +1 = 18, 2^18 = 262144   

Observe that adding 1 to the Exponent multiply its value by 2.
The inverse is true, subtracting 1, divide the Exponent by 2.

10000100 = 32, subtracting 1, becomes 10000011 = 16.

Also, shifting one bit to the left and adding 1, multiply Exponent by itself, as N^2. For example, 10000010 = 8, shifting left 10000100 = 32, plus 1 10000101 = 64 = 8^2.
So, shifting left = N * N/2.

The inverse is only true if bit E1 (last bit of Exponent) is 1, case of 10000101 (64) subtracting one and shifting right will give you the square root, 10000010 (8). The same for 10001011 (4096) subtracting one and shifting right becomes 10000101 = 64. If E1=0, results invalid, case of 10000110 (128) subtracting one, 10000101 and shifting right becomes 10000010 that is 8, if only shifting without subtracting becomes 10000011 that is 16, both invalid.

Reinforcing the idea:
0000-1110 in binary means 2^3 + 2^2 + 2^1 = 8 + 4 + 2 = 14.
x000-1110 in FP Exponent means 2^(2^3 + 2^2 + 2^1 + 1) = 2^(14+1) = 2^15 = 32768.

But you see the Exponent can only form values that are 2^n, not intermediate ones, like 5, 12, 15, 257, etc. That is where the Mantissa works. It stores fractions of the Exponent, as 2^-n, where this "n" is the Mantissa bits values.

FP bit 23 is Mantissa bit 1, so its value is 2^-1, that is 1/2, or 0.5.
FP bit 22 is Mantissa bit 2, its value 2^-2, 1/4, or 0.25, and so on.

When yout put a negative sign on the "n" as exponent of 2, it is the same as use this value to divide 1. 2^3=8, 2^-3=1/8.

But the Mantissa value is not numeric, it is a multiplicand fraction of the Exponent. For example, FP bit 23 Mantissa M1 10000000... is not 0.5, it means that the Exponent value should be added by its own Half. To understand it better, Mantissa 23 bits are all smaller than 1, they are 0.nnnn. Based on that, we need to insert a invisible integer 1. in front of it, so, Mantissa 1000000... that is 0.5 becomes 1.5. It means that the Exponent must be multiplied by 1.5

So, FP 0-10000001-1000000000.... means exponent 4, multiplied by Mantisse 1.5 = 6.
If FP 0-10000001-110000000... means 4 x (1 + 0.5 + 0.25) = 4 x 1.75 = 7

Bit 23 = 0.5  (left bit)   
Bit 22 = 0.25   
Bit 21 = 0.125    
Bit 20 = 0.0625   
Bit 19 = 0.03125   

...   
...   
Bit 1 = 0.0000001192092896 (bit FP 1)  

Now, same Mantissa of 0.75 (1100000....) will always multiply the Exponent by 1.75, no matter the value of it. Number 6, 12, 24 shares the same Mantissa of "100000...." that is 0.5, because it multiplies 4x1.5=6, 8x1.5=12, 16x1.5=24, etc.

What is the importance of that?

2. Easy Floating Point Multiplication Easy

See, if your have two numbers, with the SAME Mantissa, means both numbers will have the same multiplicand of fraction. If you want to multiply those numbers, just multiply the Exponent, divide the Mantissa shifting to the right.

For example, multiplying 6 by 24.
The 2^n Exponent of 6 is 4, Mantissa is 0.5
The 2^n Exponent of 24 is 16, Mantissa is also 0.5
Then, 6 x 24 = 144, dividing by 1.5 and again by 1.5 = 64, that is exactly 4x16 .
Divided twice by 1.5 because there are two mantissas, will be the same as dividing 144 / (1.5 * 1.5) = 144 / 2.25 = 64.
So, the new Mantissa of the multiplication result will be 0.5 * 0.5 = 0.25, or 0.5 / 2.

Curiosity, what is the FP for 144?
0-10000110-0010000000000....
what is the Exponent 10000110 means? bits at the right "000110" = 6 +1 = 7, 2^7=128
what the Mantissa of 001000000... means? 1/8 or 0.125.
So, 128 * 1.125 = 144... neat.

How Exponent of 6 multiplied by Exponent of 24 becomes Exponent of 128?
Exponent of 6 is 4 0-10000001-xxxxxxxxxx
Exponent of 24 is 16 0-10000011-xxxxxxxxxx

Each added bit at Exponent means multiplying it by 2
So, adding a bit to the Exponent of 16 turns 1000-0011 to 1000-0100 (32).
We need to multiply 16 by 4, we need to add 2 bits, it will turns from 1000-0011 to 1000-0100 (first bit) then to 1000-0101 (second bit) = 64.
As the two Mantissas are the same, just shift right it the same quantity of bits of the Exponent multiplication, 2 bits.
From 100000000... to 001000000...
Then, the result FP of multiplying "6" FP 0-10000001-1000000... by "24" FP 0-10000011-1000000... is 144 FP 0-10000101-0010000000... Exponent=128 multiplied by Mantissa 1.125 = 144.

If the Mantissas are different, the technique is different.

3. Floating Point Addition (your question)

Lets first Add easy numbers, 6 and 8 = 14

6  = FP 0-10000001-1000000000...   
8  = FP 0-10000010-0000000000....   
14 = FP 0-10000010-1100000000.... 

The Exponent of 14 is its lower integer 2^n, that is 8
The Mantissa of 14 is the fractions of 8 that try to compose the difference that is 6.
6/8 = 0.75, that is a composition of 0.5 + 0.25
So, the Mantissa of 14 will be 11000000000....
But how it happens in binary form?

There are rules.
First, If the first Exponent is smaller than the second, subtract and take the absolute difference (AD) and shift right AD bits of the Mantissa of lower number.

Exponent of 6 is 10000001, exponent of 8 is 10000010, difference is 1, so shift right one bit the Mantissa of 6. Remember that Mantissa 10000.... is 0.5, but in real is 1.5, so there is this invisible integer 1. Now you WILL need to insert this 1 in front of both mantissas, and shift right mantissa of 6 ONE bit, the difference.

Mantissa of 6 with 1. = 1.10000000....
Mantissa of 8 with 1. = 1.00000000....

Shift right 1 bit mantissa of 6 = 0.110000000
Mantissa of 8 stil the same = 1.000000000

Now ADD both

0.1100000000    
1.0000000000   
--=--------- +   
1.1100000000   

Now, it is important that the integer 1. must be exactly in that position, it could not be to the left (1x.xxxxx...) or zero in its place. If it happens, there are techniques to fix that.

Now, the original integer 1.xxx disappear, it is invisible anyway, and the final Mantissa becomes 110000000....

The new Exponent will be the bigger, in this case the exponent of the 8, 10000010.
This is the rule, while there is a larger exponent or the addition of the mantissas does not ended with integer bigger than 1, the new exponent is the same as the bigger one. If the integer of the adding result is bigger than 1, it will be 2 (10.xxxx~) then just add 1 to the Exponent and shift one bit right the whole resulting Mantissa, so it becomes 1.xxxx~. I put an example at the end of this post.

Now it is just a matter to composite Exponent + Mantissa:
0-10000010-11000000... is the FP of 14, adding 6 + 8.

Can you do alone the add of your own FP numbers below?

Your number A = 5.1243230 FP 0-10000001-01000111111101001110100   
your number B = 2.2134523 FP 0-10000000-00011011010100100110100   
Result A + B  = 7.3377753 FP 0-....  

A Exponent = 4, 10000001
B Exponent = 2, 10000000
Difference between them is 1
So, include integer 1. in front of both mantissas, and shift right 1 bit the mantissa of B.

A = 1.01000111111101001110100   
B = 1.00011011010100100110100   

Shift right 1 bit B

A = 1.01000111111101001110100   
B = 0.10001101101010010011010 

Add both

A = 1.01000111111101001110100   
B = 0.10001101101010010011010   
------------------------------ +   
    1.11010101100111100001110   

Integer continues 1, perfect.
Now, eliminate the Integer and use this Mantissa as result
Concatenate with the larger Exponent, of 4, 10000001 becomes
FP = 0-10000001-1101010110011110000111000...
That is exactly the FP of 7.3377753.

(The following was added later)
Example of adding resulting Mantissa with bits 10.xxxx~

Suppose you are adding 7 + 2 = 9

7 FP  0-10000001-11000~
2 FP  0-10000000-00000~

Exponent of 7 is bigger than 2 and the difference is 1. So lets insert the implicit integer 1 in front of both Mantissas:

7 Mantissa:  1.110000~
2 mantissa:  1.000000~

Shift smaller (2) Mantissa right one bit and add both.

7 Mantissa:  1.110000~
2 mantissa:  0.100000~
----------------------- +
Resulting:  10.010000~

See, there is a 2 (bits 10.xxx~) as the implicit integer of the resulting Mantissa. As said before, this implicit 1 represent one time the Exponent. Now, this 2 (bits 10.xx~) represent TWO times the Exponent. We need to transfer this extra ONE time back to the Exponent, adding 1 to the Exponent, that is in fact multiplying the exponent by 2. By doing so, we need to divide the Mantissa by 2, shifting it right one bit.

So, the resulting Mantissa 10.010000~ will become 1.001000~
The final FP will be 0-10000010-0010000~ that is 9.

Easy, isn't it?

Now lets do it in Assembly AVR, usando only 4 registers (32 bits) for each FP and another 4 registers for the answer (thanks Peter for catching the "3" typo).

查看更多
放我归山
3楼-- · 2019-12-16 19:51

As Michael pointed out in a comment, you are performing regular old integer addition on the two numbers. The algorithm you are using assumes that your numbers are unsigned or signed (two's complement) numbers.

You need to figure out the format of your floating point numbers before you can really think about how to add them together. A floating point number will generally be represented with an exponent, mantissa, and maybe a sign bit. Those things might depend on what exact compiler you are using and its settings. Maybe your compiler's floating point numbers conform to an IEEE floating point standard. Or if these floating numbers are not coming from any compiler, then you should find out what code is producing them and study that code so you can know what format they are in.

You should reconsider whether you really need floating point numbers. Maybe integers are good enough.

If you really need floating point numbers, you should try compiling a C program that does floating point addition, and then look at its disassembly listing as a starting point.

查看更多
小情绪 Triste *
4楼-- · 2019-12-16 19:57

Most CPUs (including AVR) do not store type information, therefore you must use different instruction for different types. add and adc for integers, and different instruction for floating point.

If the CPU has no floating point instructions, then there may be a library subroutine to do it for you.


Interestingly you can use the same add for signed(2s complement) and unsigned. But not the same multiply or divide.

查看更多
走好不送
5楼-- · 2019-12-16 20:00

I do not prefer to convert it to hex and then divide by bytes. Good way:

.EQU dwi = 5124323; define the constant
 LDI r21 ,LOW(dwi) ; The lowest 8 bits to R21
 LDI r22,BYTE2(dwi) ; bits 8 .. 15 to R22
 LDI r23 ,BYTE3(dwi) ; bits 16 .. 23 to R23
 LDI r24 ,BYTE4(dwi) ; bits 24 .. 31 to R24

;and next variable

.EQU dwj = 22134523

 LDI r25 ,LOW(dwj) ; 
 LDI r26 ,BYTE2(dwj)  
 LDI r27 ,BYTE3(dwj) 
 LDI r28 ,BYTE4(dwj) 

And to correct addition you should begin from lowest bytes (in this case r21 and r25), but you started with highest (the order is rigth-to-left)

add r21, r25
adc r22, r26
adc r23, r27
adc r24, r28

my recommends to read

查看更多
登录 后发表回答