Double and float variable max limit problem
todieforteo
Posts: 7
in Propeller 1
Hi everyone,
I have a quicstart board. I am using double and float variable for meter calculating, but when I use float variable , it is get max value 5242,00. Then I use double variable it is get max value 8192,00. I know this is not the maximum value of these variables. I want to calculate higher meter values.
Please help me.
Thanks in advance.
I have a quicstart board. I am using double and float variable for meter calculating, but when I use float variable , it is get max value 5242,00. Then I use double variable it is get max value 8192,00. I know this is not the maximum value of these variables. I want to calculate higher meter values.
Please help me.
Thanks in advance.
Comments
To get some more precision, try using fixed-point arithmetic: use 32-bit ints for metre1 and pulse_distance, and set pulse_distance = 1. When you interpret the value of metre1, remember that the stored value is the true value divided by 0.000305: you need to multiply it by 0.000305 before displaying it. You can do this last multiplication using floats if you're lazy, but there are ways to do it without any floats.
As Electrodude says, a Single's more limited mantissa is getting in the way. You need about 34 bits but a Single only provides 24 bits. How it will be working is it'll start off accumulating correctly but as you exceed the 24-bit capacity the lowest bits get rounded off and the new additions will also be rounded, maybe truncated. Result is rubbish.
Aside from that detail, what result were you expecting? 1000.00 presumably.
The hard coded 305 micron preset for the encoder pulse increments looks suspiciously like the number of millimetres in a foot rather than something suited to a metre.
You'll have to multiply your entire system by 10^6, but just for the setup. Once it's running the math is the same only with whole numbers.
Since you are only printing 2 decimal digits:
1) Print all but the last 6 digits
2) Print a decimal
3) Print the the two "decimal" digits
Your print will be slower, but your math will be faster and you will experience no rounding errors.
Your max range will be 18,446,744,000,000
If this was applied to an integer the adder circuits will roll over back to zero and carry on. It's clear when a roll over occurs and needs more bits. With floats it's not so clear you've hit the precision limit. The errors just grow until it stops accumulating altogether.
To summarise, floating-point doesn't suit this application, fixed-point (Integers) is the better choice.
Only after the data is captured should you be processing into floats for display/analysis.
This compiles just fine. Think I got it all. There was an errant variable sayac that I commented out.
That does not work. You have metre1 as type uint64_t. That means it can not be negative. The "metre1 -= pulse_distance;" will underflow!
Personally I would just count the pulses up and down in steps of 1. No point in wasting bits by incrementing/decrementing by anything bigger than 1.
When you want to use that count as a distance in meters multiply it by the appropriate scaling factor.
Better still. Don't use floats or doubles. Use fixed point arithmetic. Everything can be done using integers scaled up by an appropriate power of 2.
It'll work fine because there isn't any attention paid to the arithmetic flags in the ALU. The 2's-complement circuit works the same with signed and unsigned. There'll probably be a compile time warning, but no ill effects.
Your increment by one is ideal solution though.
EDIT: Typo
Consider the following code:
Which outputs:
0.000305
5626256833904640.000000
Changing count to int64_t produce the right result.
There are no warning from the compiler in either case.
You might have to explain that one.
Certainly the C language defines what should happen when unsigned ints overflow or underflow.
On the other hand overflow of signed integers is undefined behavior in C. Anything could happen and it would all be C compliant.
But, even if that unsigned underflow I show above is defined behavior and legitimate C code, the code as a whole is not doing what we want. It's wrong, a bug.
Actually it doesn't. C follows the usual CPU convention of being agnostic as to whether ints are signed or unsigned for addition and subtraction, so those operations are "circular." Whether MSB set means negative or bigger is determined by how you print it out and how you do other operations like multiply and divide. The actual addition and subtraction operations are the same and roll over. Confusion on this point is why 32-bit systems are often considered to be limited to 2 gigabytes instead of 4 -- much code invisibly uses signed math for multiplication, causing errors in the calculation of addresses with MSB set.
I do not know all the definitions. Can you please recommend a pdf on the topic?
I have not replied yet because I feared that I had made a mistake. So I tested it. Regardless of the definitions, Heater was correct on two points:
1) The underflow that I was counting on failed and an int64_t is the correct choice
2) I should have made the logical jump to incrementing and decrementing by 1 as it allows for the maximum range and any adjustments can be made right before printing as that only happens once
So same code basically, just make it an int64_t, increment by 1, cast double and multiply the result by 305/10^6
Did I understand the fix correctly @heater?
https://www.iso.org/standard/57853.html
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf
https://isocpp.org/std/the-standard
Contrary to what localroger says, wraparound behavior using unsigned integers is legal and well-defined, and there are code idioms that deliberately use it. On the other hand, C and C++ have undefined semantics for signed overflow and shift past bitwidth.
The above phrasing shamelessly borrowed from this great document on the subject:
https://www.cs.utah.edu/~regehr/papers/overflow12.pdf
As localroger says, there is confusion on this point.
Sounds like you have the hang of it mikeologist.
Sweet, thanks
I'll try to update OPs code and tag you
Hi everyone,
firstly, I am thank you for your helps. I solved my problem using uint64_t variable.but I use a lot of mathematical operation on another cogs and ı don't want to slowing my program. Another problem, I use a 2500 pulse incremental rotary encoder. quick start board works good until 120 m/min.but it is can not count the pulses when the speed exceeds 120 m / min. does the quick start board have a high speed counter pin?
Here you are reading the pin and using a total of 4 clocks to do so.
Read about the counter in the prop manual. You can find loads of posts here on how to use it. The counter is waaaay faster.
I don't have a C example handy. I use PASM directly.