Author Topic: Calculating with real numbers without FPU  (Read 20451 times)

0 Members and 1 Guest are viewing this topic.

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Calculating with real numbers without FPU
« on: January 23, 2019, 03:36:35 pm »
If we have a microcontroller which does not have an FPU. How would we calculate:

  • 1.713 * 0.0514
  • 1.713 + 0.0514

Thanks.
 

Online helius

  • Super Contributor
  • ***
  • Posts: 3779
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #1 on: January 23, 2019, 03:47:44 pm »
If your numbers are all in about the same range, fixed point is easiest. That is basically the same as computation on integers, where you choose a small power of 2 to be your unit.

For example, 1.713 can be represented as a fixed-point with 12 fraction bits:
Code: [Select]
1 * (1<<12) + 2920 == 1.713 * (1<<12)Then addition and subtraction works as normal, and multiplication or division also requires a 12 bit shift.
 
The following users thanked this post: nForce

Offline rhodges

  • Frequent Contributor
  • **
  • Posts: 364
  • Country: us
  • Available for embedded projects.
    • My public libraries, code samples, and projects for STM8.
Re: Calculating with real numbers without FPU
« Reply #2 on: January 23, 2019, 03:52:42 pm »
Usually, I can get a "good enough" result by multiplying the floating point number by 2^N. Then use that integer and shift or drop N bits afterwards.

1.713 * 2^16 = 112263
0.0514 * 2^17 = 6737

112263 * 6737 = 756315831
756315831 >> 33 = 0 (less than 1)

If you want to use the fractional part of the result, don't shift or drop all N bits.
Currently developing embedded RISC-V. Recently STM32 and STM8. All are excellent choices. Past includes 6809, Z80, 8086, PIC, MIPS, PNX1302, and some 8748 and 6805. Check out my public code on github. https://github.com/unfrozen
 
The following users thanked this post: nForce

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Re: Calculating with real numbers without FPU
« Reply #3 on: January 23, 2019, 04:11:56 pm »
Hmm, ok but what about for example this fixed point format: https://en.wikipedia.org/wiki/Q_(number_format) ?
 
The following users thanked this post: rhodges

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3549
  • Country: ca
Re: Calculating with real numbers without FPU
« Reply #4 on: January 23, 2019, 04:12:43 pm »
You can do floating point calculations without FPU. Usually, the C compiler will have built-in software libraries to do this. So, you won't even notice the difference (except for performance, of course).

Whether you should use floating point is a different questions. In most cases, you can use scaled integers instead. Thus you wouldn't calculate floating point things on a small MCU in the first place.
 
The following users thanked this post: nForce

Offline rhodges

  • Frequent Contributor
  • **
  • Posts: 364
  • Country: us
  • Available for embedded projects.
    • My public libraries, code samples, and projects for STM8.
Re: Calculating with real numbers without FPU
« Reply #5 on: January 23, 2019, 04:49:33 pm »
@nForce: Thanks for the link. It is better than my example.

Here is an example to convert liters to gallons and get the ASCII character for the tenths gallons. It is "close enough" for my needs.

Code: [Select]
/******************************************************************************
 *
 *  Convert liters to gallons
 *
 *  in: liters
 * out: gallons * 32 (low 5 bits for decimal point)
 */

int conv_gallons(int liters)
{
    unsigned long temp;

    temp  = (unsigned int)liters;
    temp *= 541;
    temp >>= 6;

    return temp;
}

/******************************************************************************
 *
 *  Get decimal point char from bottom 5 bits
 *
 *  in: 5 bits of fractional number
 * out: decimal character
 */

char conv_point(char frac)
{
    return ((frac * 10) >> 5) + '0';
}
Currently developing embedded RISC-V. Recently STM32 and STM8. All are excellent choices. Past includes 6809, Z80, 8086, PIC, MIPS, PNX1302, and some 8748 and 6805. Check out my public code on github. https://github.com/unfrozen
 
The following users thanked this post: nForce

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17807
  • Country: fr
Re: Calculating with real numbers without FPU
« Reply #6 on: January 23, 2019, 05:14:29 pm »
As NorthGuy said, you can do floating point on pretty much most MCUs. Those without an FPU will have terrible performance with FP, but that may be adequate for your needs.

If performance is an issue, use integers instead. Either through fixed point arithmetic, or just by rewriting your calculations with scaled integers (both are close).

Yet another, less common approach is to express the numbers as rationals N/M which will avoid approximations as long as all your numbers are rational to begin with (but it will usually require the use of "large integers"). Has its uses, but it's not a general-purpose solution so you'd need to make sure it's relevant for what you need to calculate. If you're just considering using floating point numbers (but won't for performance reasons), it's probably not the approach for you.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Calculating with real numbers without FPU
« Reply #7 on: January 23, 2019, 05:24:21 pm »
softfloat
 

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Re: Calculating with real numbers without FPU
« Reply #8 on: January 23, 2019, 05:55:47 pm »
Ok, let's forget that we have an FPU. What about if we use old microcontrollers.
And rhodges this a great example:

Quote
1.713 * 2^16 = 112263
0.0514 * 2^17 = 6737

What if we have only a 4-digit display? Now what? Now we can't display 112263.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 30279
  • Country: nl
    • NCT Developments
Re: Calculating with real numbers without FPU
« Reply #9 on: January 23, 2019, 05:59:09 pm »
If we have a microcontroller which does not have an FPU. How would we calculate:

  • 1.713 * 0.0514
  • 1.713 + 0.0514

Thanks.
By using soft floating point. It comes standard with every C library. There is one downside: you will need more flash and the speed will be slower. If your application can tolerate that, then you are fine and I wouldn't bother with using fixed point math. If you use an ARM microcontroller it is likely fast enough to use floating point in realtime scenarios as well. I'd try first to see if you get the required performance using soft floating point and only optimise if the performance isn't good enough.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline tsman

  • Frequent Contributor
  • **
  • Posts: 599
  • Country: gb
Re: Calculating with real numbers without FPU
« Reply #10 on: January 23, 2019, 06:21:03 pm »
What if we have only a 4-digit display? Now what? Now we can't display 112263.
That is a really vague question. You as the designer need to decide what is appropriate as a workaround as this is specific to your device. If those digits are essential then you'll need to redesign your device to have a bigger display. If you don't care then truncate the extra digits when displaying them.
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 4849
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #11 on: January 23, 2019, 06:24:05 pm »
I frequently run into cases where I am only doing a small amount of floating point computation.  Perhaps just formatting for display, or applying a rescaling to a low speed ADC such as a power supply monitor.  In that case I use soft float if it will fit in the available flash memory.  It is easy as flipping a switch, completely obvious what you are doing, and you don't have to worry about manually scaling multiplication.  It also lets you use the rest of the standard math library, such as trig and exponent functions which might be useful -- for instance converting linear amplitude to dB or computing sqrt(a^2+b^2).  There are fixed point algorithms for all of those, but if the provided math libraries work, just use them.

For even slightly performance critical cases, fixed point is the way to go.  If you need the dynamic range of floating point and you care at all about performance you need a microcontroller with an FPU.

There as some applications where fixed point is actually desirable or needed.  For instance, it is usually desirable to implement FIR filters in fixed point.  A FIR filter has unity gain if the coefficients sum to 1. With floating point if the exponent changes you can get (small) signal dependent gain variation which might be a problem for you.  A high order FIR boxcar averager can be implemented efficiently by adding the current item and subtracting the Nth previous item.  This reduces N operations per cycle to 2 (at a cost of N memory).  But this doesn't work well with floating point as the subtraction won't exactly cancel the addition if the floating point exponent changes.

Obviously correctness is more important than convenience. If you application requires fixed point use that.
 

Offline 0xdeadbeef

  • Super Contributor
  • ***
  • Posts: 1903
  • Country: de
Re: Calculating with real numbers without FPU
« Reply #12 on: January 23, 2019, 06:48:05 pm »
Fixed point integer format is typically way to go since software float is slow as hell. So with any kind of real time requirement, software float is usually not an option.

Also keep in mind that floating point doesn't magically increase the precision. For 32bit floating point, there are still only 1<<32 different values but the range if fixed. So in a smaller range, a cleverly implemented fixed point calculation will be more precise than a float implementation of the same width (e.g. 32bit). Many people aren't even aware that any integer greater than 1<<24 can't be exactly represented in 32bit float. E.g. the integer 16777216 can be represented precisely in 32bit float, but the integer 16777217 can't. And of course the inaccuracy increases for larger (absolute) values. E.g. towards the end of the unsigned 32bit integer range, there are no integer values between 4294967040 and 4294967296 than can be represented. That's a gap of 254 integer numbers that simply can't be represented.

What people also tend to forget is that float calculations are not as idiot proof as integer calculations. E.g. while most CPUs saturate integer calculations like n/0 to return the largest possible integer with correct sign, this is not necessarily the case for float. Actually n/0 is +/-infinity in IEEE float (actual implementation might differ). Also you can easily end up with denormalized ("subnormal") numbers that still have a (very small) value but can't be used for further calculations. Finally, 0/0 officially results in "not a number" where there can be "signaling" and "quiet" NaNs. In many cases, you either have to check your values for INF, NaN or subnormals or have to implement exceptions handlers which handle numerical exceptions. In my experience, 90% of people who use floating point calculations have not the slightest idea about the possible implications.
Trying is the first step towards failure - Homer J. Simpson
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3549
  • Country: ca
Re: Calculating with real numbers without FPU
« Reply #13 on: January 23, 2019, 07:06:20 pm »
Ok, let's forget that we have an FPU. What about if we use old microcontrollers.
And rhodges this a great example:

Quote
1.713 * 2^16 = 112263
0.0514 * 2^17 = 6737

What if we have only a 4-digit display? Now what? Now we can't display 112263.

If a big part of your project is display, use units that you can display. For example, instead of 1.713 V use 1713 mV. It lets you do all the integers, but at the same time the display is easy - you only need to insert a dot (or a comma if you're in Europe).
 
The following users thanked this post: JPortici

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Re: Calculating with real numbers without FPU
« Reply #14 on: January 23, 2019, 09:16:43 pm »
If I have 1.5 and 0.5 in a format Q5.11.  How would I binary multiply these two numbers and check the result?

According to wikipedia I compute 1.5 * 2^-11 and 0.5 * 2^-11. Then I multiply these two numbers, is it correct? How would I check if it's correct?
 

Online helius

  • Super Contributor
  • ***
  • Posts: 3779
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #15 on: January 23, 2019, 10:01:16 pm »
If it helps, you can imagine an analogous system of fixed-point decimals.
Let's say that we have made our "unit" 1/1000. So the smallest representable amount is 0.001, which we can call, "1". So to represent 2, we would multiply the integer part by 10^3: "2,000". To represent 3.5, we multiply the integer part by 10^3, and then add the fraction part, which is the solution to the equation \$ 0.5 = {x\over 1000} \$; which gives us "3,500".
Straight multiplying "2,000" by "3,500" will give us a product with as many digits as both multiplicands have together. So the result would be "7,000,000", which we know is incorrect: it should be "7,000". We ended up with six fraction digits, when what we needed was just three (because the unit is 1/1000). So we need to "decimal shift" right by three digits to fix that.

In binary fixed point, the same is true. If we pick a unit of 1/1024 or \$ 2^{-10} \$, then we have ten binary fraction digits in each variable. The smallest representable amount is 1/1024, which we call "1". To represent 2, we multiply the integer part by 2^10, or just shift left by 10 bits:
Code: [Select]
2<<10 == 2048To represent 3.5, we multiply the integer part by 2^10, or just shift left by 10 bits; and add the fraction part, which is the solution to the equation \$ 0.5 = {x\over 1024} \$; which gives us
Code: [Select]
(3<<10) + 512 == 3584Straight multiplying "2048" by "3584" would give us "7340032", which we know is wrong, because the result should fit in 13 bits, but it takes 23. We need to binary shift right by 10 bits to fix it: "7168", which is equal to 7 * 2^10.
« Last Edit: January 23, 2019, 10:03:22 pm by helius »
 
The following users thanked this post: nForce

Offline iMo

  • Super Contributor
  • ***
  • Posts: 6919
  • Country: li
Re: Calculating with real numbers without FPU
« Reply #16 on: January 24, 2019, 10:14:40 am »
I had 32bit floating point math (incl transcendentals..) in one of my pic16f88 projects. The library was 3.5kB large, afaik. Unless you go with a tiny MCU with 16bytes ram and 512bytes flash use a built-in library, every C has got it..
Readers discretion is advised..
 

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Re: Calculating with real numbers without FPU
« Reply #17 on: January 24, 2019, 04:18:22 pm »
Isn't the format Q5.11 just a format of a 16-bit word, where the first 5 bits is an integer number, and rest (11 bits) is the decimal?

So for Q5.11 = 1.5 and Q5.11 = 0.5, how can we write it in the Q5.11 format?
 

Online helius

  • Super Contributor
  • ***
  • Posts: 3779
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #18 on: January 24, 2019, 04:54:58 pm »
Isn't the format Q5.11 just a format of a 16-bit word, where the first 5 bits is an integer number, and rest (11 bits) is the decimal?
Not decimal, but binary fraction.
 
The following users thanked this post: nForce

Offline IDEngineer

  • Super Contributor
  • ***
  • Posts: 1981
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #19 on: January 24, 2019, 04:56:22 pm »
In fairness, software-based floating point can be quite reasonable. As just one example, I was doing a project based on the Microchip PIC18F and needed some FP trig. I figured I'd have to implement it in integer, but wrote and timed it (with a scope) just to see what the FP libraries could deliver. Turned out not only to be fast enough, but remarkably accurate... as good as my HP calculator for the same calculations. (Yes, I know, FP has quantization errors but this application didn't need to worry about that many digits past the decimal point.)

Interestingly, the 32 bit library was FASTER than the 24 bit version. Didn't expect that.

On the flip side, I definitely used integer math for the IIR filters on that same project. It's all about understanding what you're trying to do and what your hardware and libraries can deliver. You can guess, or (like me) you can run the tests and gather actual data to make an informed decision for each use case. In the example above, a slight change to the architecture helped a lot - I switched to maintaining the (frequent) intermediate data in integer form and only incurred the overhead of the FP trig operations when it was actually (and infrequently) necessary.

Bottom line: Don't automatically dismiss software FP. It can be better that you expect, particularly if you architect your overall project properly.
 

Offline dave j

  • Regular Contributor
  • *
  • Posts: 172
  • Country: gb
Re: Calculating with real numbers without FPU
« Reply #20 on: January 24, 2019, 05:06:23 pm »
Isn't the format Q5.11 just a format of a 16-bit word, where the first 5 bits is an integer number, and rest (11 bits) is the decimal?

So for Q5.11 = 1.5 and Q5.11 = 0.5, how can we write it in the Q5.11 format?
As helius said, you need to think of binary fractions. Essential Mathematics for Games and Interactive Applications has a good description of fixed point numbers and handily that chapter is available online here.
I'm not David L Jones. Apparently I actually do have to point this out.
 
The following users thanked this post: nForce

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17807
  • Country: fr
Re: Calculating with real numbers without FPU
« Reply #21 on: January 24, 2019, 05:10:05 pm »
So for Q5.11 = 1.5 and Q5.11 = 0.5, how can we write it in the Q5.11 format?

Just multiply the number by 2^11. And make sure the integer part can be represented with only 5 bits.

Eg.:
1.5 -> 3072
0.5 -> 1024

Sum: 1.5 + 0.5 -> 3072 + 1024 [you'll need a 16-bit + 16-bit -> 16-bit + carry addition]  -> 4096 [which is 2 in Q5.11]
Product: 1.5 * 0.5 -> 3072 * 1024 [you'll need a 16-bit x 16-bit -> 32-bit multiply] / 2^11 [a right-shift of 11 positions] -> 1536 [which is 0.75 in Q5.11]

 
The following users thanked this post: nForce

Offline nForceTopic starter

  • Frequent Contributor
  • **
  • Posts: 393
  • Country: ee
Re: Calculating with real numbers without FPU
« Reply #22 on: January 24, 2019, 05:40:57 pm »
So for Q5.11 = 1.5 and Q5.11 = 0.5, how can we write it in the Q5.11 format?

Just multiply the number by 2^11. And make sure the integer part can be represented with only 5 bits.

Eg.:
1.5 -> 3072
0.5 -> 1024

Sum: 1.5 + 0.5 -> 3072 + 1024 [you'll need a 16-bit + 16-bit -> 16-bit + carry addition]  -> 4096 [which is 2 in Q5.11]
Product: 1.5 * 0.5 -> 3072 * 1024 [you'll need a 16-bit x 16-bit -> 32-bit multiply] / 2^11 [a right-shift of 11 positions] -> 1536 [which is 0.75 in Q5.11]

Ok, thanks. So if we would see a 16-bit register where we use Q5.11 format for 1.5, then when we would convert this 16 bit register to a decimal we would get 3072? Do I now understand?
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 13116
  • Country: us
Re: Calculating with real numbers without FPU
« Reply #23 on: January 24, 2019, 06:22:19 pm »
Isn't the format Q5.11 just a format of a 16-bit word, where the first 5 bits is an integer number, and rest (11 bits) is the decimal?

So for Q5.11 = 1.5 and Q5.11 = 0.5, how can we write it in the Q5.11 format?

You have 1.5 (decimal) = 1.1 (binary), and 0.5 (decimal) = 0.1 (binary).

Then you multiply them in binary (normal long multiplication): 1.1 x 0.1 = 0.11 (binary).

Lastly convert back to decimal: 0.11 (binary) = 0.75 (decimal).

Note:

In Q5.11 format, 1.1 (binary) = 00001.10000000000 and 0.1 (binary) = 00000.10000000000

When you do the fixed point multiplication in binary you will need to be aware of overflow or lost precision.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Calculating with real numbers without FPU
« Reply #24 on: January 24, 2019, 06:35:05 pm »
fixepoint needs saturating math
made in software or in hardware

this, plus a fine-tuning of the algorithm.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->