4

I m trying to find how to make a division in ARM since there is no DIV command. If that can be done by multiplication of a float number [/9 = *0.09], by subtraction or by the use of a library. Any way would do.

Currently I am doing division using subtraction using a loop like this but I loose the decimals:

MOV R0,#70 ;Fahrenheit Temperature
SUB R1,R0,#32 ; Subtracting 32
MOV R4,#0 ;Counter

LOOP 

   ADD R4,R4,#1; Counter+1 ->Is the answer of the division without decimals
   SUB R1,#9
   CMP R1,#0
   BPL LOOP
   MOV R1,R4

So basically what I am doing is that I have temperature 70, I subtract 32 and I get 38. Then in the loop I take 9 each time till the reminder is smaller than 9. The answer using normal division is 4.22222. Here I get 5. So my result is not as accurate.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Antreas Solou
  • 91
  • 1
  • 3
  • 9
  • possible duplicate of [Fast Division on GCC/ARM](http://stackoverflow.com/questions/16218228/fast-division-on-gcc-arm) – artless noise Nov 07 '13 at 19:34
  • 1
    It is better to multiply by something like (2^16/9~=7282) and then shift by 2^16 on the result. You have to know the range of values and this works only for a **fixed** division. – artless noise Nov 07 '13 at 19:39
  • Other related quesions: [Integer division on ARM](http://stackoverflow.com/questions/8348030/integer-division-on-arm), [Assembly mod algorithm](http://stackoverflow.com/questions/938038/assembly-mod-algorithm-on-processor-with-no-division-operator); look at the related list at the side of the question. – artless noise Nov 07 '13 at 19:43
  • My ARM has a division instruction...why doesn't yours? Is there perhaps a little more information you could give us? –  Nov 07 '13 at 19:45
  • 1
    http://homepage.cs.uiowa.edu/~jones/bcd/divide.html and just do that for any other number. yes you can use fixed or float to multiply by 1/9th for example. – old_timer Nov 08 '13 at 00:24

2 Answers2

5

If you just want to divide an integer value in r0 by 9 you can approximate that with:

ldr r3,=0x1C71C71D   # 1C71C71D == (2^32 / 9) + 1
umull   r9,r3,r0,r3

r3 now contains the integer part of the quotient, and r9 contains the fractional part scaled by 2^32. To get the remainder you'd just multiply the integer part of the quotient by 9 and subtract the result from the original value.

Michael
  • 57,169
  • 9
  • 80
  • 125
  • 2
    This is [divide by multiply](http://stackoverflow.com/questions/5558492/divide-by-10-using-bit-shifts). Read more [here](http://stackoverflow.com/questions/16218228/fast-division-on-gcc-arm) – phuclv Nov 08 '13 at 00:31
  • @AntreasSolou: `umull` multiplies two 32-bit numbers to form a 64-bit result (split into two registers). So what the code does is form a 32.32 [fixed-point number](http://en.wikipedia.org/wiki/Fixed-point_arithmetic) in `r3` (whole part) and `r9` (fractional part) that is equal to `(r0 << 32) / 9`. – Michael Nov 08 '13 at 07:05
  • For exact division that works for all `uint32_t` inputs, see GCC8.2's output: https://godbolt.org/z/-PVI_Q uses a different multiplier that needs a right shift by 1 after umull, but that's all. – Peter Cordes Apr 10 '19 at 07:54
2

Michael's answer is right if you divide the number by a constant and you need an integer result. You won't get the fraction part like you want.

If you need a floating-point result you'll need a floating-point division function, which is not easy to implement in software and asm on architectures without FPU. ARMv7 and above have FPU/SIMD by default, some ARMv6 and below also have FPU so you can divide it directly in hardware

A fixed-point solution may be easier, just divide the number like normal integer division but remember to adjust the result after calculation. Of course fixed-point number won't have large dynamic range like floating-point but in your case I think the range is enough. You can also multiply the remainder by 10n, with n is the number of digits after decimal sign you need, then divide it with the above divisor again to get the fractional part

For example to get the result of 22/9 with 3 digits of precision do as follow:

22/9   = 2 remains 4
4*10^3 = 4000
4000/9 = 444
→ 22/9 = 2.444

To get more precision, just multiply the remainder with a larger power of 10

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • The more complicated multiply trick ([Why does GCC use multiplication by a strange number in implementing integer division?](//stackoverflow.com/q/41183935)) actually is a fixed-point multiplicative inverse, so you could use that to get some fraction bits. Normally you only keep the integer part from the high half of the full result. Michael's answer looks like something simpler than what gcc uses for exact division: https://godbolt.org/z/0YfBFt which involves a shift after umull. – Peter Cordes Apr 10 '19 at 07:53