|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Tue Mar 01, 2011 9:14 am
1/100th is too precise? |
In the below example, skills are represented on a scale of 0.00-100.00.
Is there a reason why $change will not show having a value of 0.01?
Code: |
<trigger priority="200" repeat="true" id="1">
<pattern>([%s%w]) (%d.%d)</pattern>
<value>$skill=%trim(%1)
$level=%2
$change=%float($level)-%float(@skills.$skill)
#IF ($change) {#PRINT {Increase! $change in $skill}}
#ADDKEY skills {$skill=$level}</value>
</trigger> |
The following two statements have different answers, so the bug is not even consistently displaying wrong.
#SAY %float(11.23-11.22)
#SAY %float(23.63-23.62) |
|
_________________ Discord: Shalimarwildcat |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Mar 01, 2011 12:29 pm |
I noticed something odd where after, say, 4 or so decimal places, it begins to try and store the values in scientific number form, at least in database records, which was extremely aggravating to deal with. I've no idea why it's having issues with two decimal places though.
|
|
|
|
Rahab Wizard
Joined: 22 Mar 2007 Posts: 2320
|
Posted: Tue Mar 01, 2011 1:38 pm |
The answer is in the nature of floats. Floats are not exact. You probably already know this. Due to the binary nature of floats in the computer, there is a slight error when translating a decimal float into binary. Then, when doing arithmetic calculations which in decimal appear equivalent, the error in the binary values results in very tiny differences in the result. In your example, %float(11.23-11.22) might result in 0.009999999...99, while %float(23.63-23.62) might result in 0.10000000...01 (examples only--the actual values will be different, and may even be different on different computers!). Comparing these numbers will then show them not to be equal. This is true in all programming languages, and is an inherent limitation on using floats. This is why many languages have an 'approximately equal to' operator for floats.
To solve this, you will have to change them out of floats. Multiply the values by 100, round off, and convert to int for your comparison. |
|
|
|
Erasmus Wanderer
Joined: 04 Aug 2004 Posts: 82 Location: Philadelphia
|
Posted: Tue Mar 01, 2011 2:15 pm |
Don't know if this will work, but you could also try putting the %norm() function around your calculation.
I.e:
#SAY %norm(%float(11.23-11.22))
#SAY %norm(%float(23.63-23.62)) |
|
_________________ Erasmus |
|
|
|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Tue Mar 01, 2011 2:40 pm |
Yet calculators get around these limitations on a daily basis...
Finding a kludge for this error is simple enough...
But i don't want to have to have my code doing tricks and flipping the numbers just to show 0.01 - this is BASIC math, CMUDPro should be capable of this |
|
_________________ Discord: Shalimarwildcat |
|
|
|
Rahab Wizard
Joined: 22 Mar 2007 Posts: 2320
|
Posted: Tue Mar 01, 2011 5:17 pm |
Calculators do _not_ get around these limitations. Calculators round things off when they display the results to you. The limitations only show up when you use comparison operators, or other things that calculators do not have. This is basic math in the decimal world, but it is _not_ a trivial problem when dealing with floats in the binary world. As I said, all programming languages have this problem. It is fundamental to binary floats. How do you suggest that the problem be solved?
As an example:
Code: |
11.23 in binary: 1011.00111010111000010100011110101110...
11.22 in binary: 1011.00111000010100011110101110000101...
Difference: 0.00000010100011110101110000101001...
0.01 in binary: 0.00000010100011110101110000101000...
Converting the binary values above to decimals:
11.23: 11.229999999981374
11.22: 11.21999999997206
Difference: 0.0100000000093132
0.01: 0.00999999977648258
|
How do you expect Cmud (or any other programing language) to know that the difference should be precisely 0.01? All the program knows is binary. As I said before, this is a fundamental problem of using binary floats. It simply cannot recreate decimal values with precision. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Mar 01, 2011 5:46 pm |
Quote: |
CMUDPro should be capable of this |
This is why CMUD gives you the %round function and the %norm function. Use them.
CMUD already handles these floating point issues when performing comparisons between numbers (such as #IF (@a = @b) ...)
These are not kludges. As Rahab mentioned, this is the case in ANY programming language, not just zScript. It's something you learn to deal with in Programming 101 class.
Also, CMUD isn't a calculator. |
|
|
|
Rahab Wizard
Joined: 22 Mar 2007 Posts: 2320
|
Posted: Tue Mar 01, 2011 6:09 pm |
I'd forgotten that Cmud automatically norms floats in comparison operations. Puts it one up on a lot of programming languages!
|
|
|
|
MattLofton GURU
Joined: 23 Dec 2000 Posts: 4834 Location: USA
|
Posted: Tue Mar 01, 2011 11:05 pm |
Quote: |
Also, CMUD isn't a calculator.
|
You perhaps didn't aim for that goal, but I'll have you know that CMud is the mother of all calculators in my eyes. If I ever have to go to a calculator website or open up the Calculator utility in Windows, I always turn to CMud instead and use that (or spend the time building a new function or whatever so that I can use CMud the next time). |
|
_________________ EDIT: I didn't like my old signature |
|
|
|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Wed Mar 02, 2011 9:10 pm |
Well.. %norm doesn't seem to change the data much at all
%round only returns integers.
Essentially you are telling me there is no way to do this precisely without converting it to integer math?
A calculator may be doing all these tricks inside its (incredibly small and weak) computer mind, but i bet i can punch in 22.33 - 22.32 and get 0.01 regardless of brand or age.
P.S. I did find a way, although I don't see why it needs me to tell it to do this: %format(&3.2f, $change)
P.S.S. Granted, i only program as a hobby... but i always just inherited someone else's math code into my programs, so I never noticed issues with floating point math.. it just never came up. |
|
_________________ Discord: Shalimarwildcat |
|
|
|
Rahab Wizard
Joined: 22 Mar 2007 Posts: 2320
|
Posted: Wed Mar 02, 2011 9:27 pm |
Quote: |
A calculator may be doing all these tricks inside its (incredibly small and weak) computer mind, but i bet i can punch in 22.33 - 22.32 and get 0.01 regardless of brand or age. |
That is only because the calculator only shows a small fraction of the number of digits it actually calculates values to. In other words, it rounds it off. It will never show you those last 30 digits (or whatever), where the discrepancy shows up. It doesn't even try to _remember_ those last digits after the calculation is done. It does the calculation out to X digits (say, the decimal equivalent of 100), converts it to decimal, rounds it off (say, to 50 digits), stores that value in its register, and displays the result. Floats on a computer don't work that way. Float mathematics depends on the low-level operations within the computer chip itself, beyond the reach of any programming language. This is why different chips can actually produce different values in the nth digit in float calculations. To simulate in Cmud or another programming language what a calculator does, you use %format, as you described above. |
|
|
|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Wed Mar 02, 2011 9:34 pm |
#SAY %norm(%float(11.23-11.22))
0.00999999977648258
#SAY %format(&3.2f, %float(11.23-11.22))
0.01
#SAY %format(&3.9f, %float(11.23-11.22))
0.010000000
Once i format it, regardless of the decimal precision i ask for, it always gives 0.01.
Should not the 9 decimal precision show 0.009999999, given the unformated value?
Granted... i like seeing the true value, but i don't understand why the results are changing.
//Nevermind, it is rounding to the decimal here instead of truncating as &3.13f shows. |
|
_________________ Discord: Shalimarwildcat |
|
|
|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Wed Mar 02, 2011 9:50 pm |
After a bit of research I came across this...
The "decimal" data type of the C# and Python (programming language), and the IEEE 754-2008 decimal floating-point standard, are designed to avoid the problems of binary floating-point representations when applied to human-entered exact decimal values, and make the arithmetic always behave as expected when numbers are printed in decimal.
Is there an equivalent in perl that could be added to CMUD? |
|
_________________ Discord: Shalimarwildcat |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Mar 03, 2011 5:15 pm |
I have no plans to add a "decimal" type to CMUD, sorry. That would be a huge amount of work.
%norm "fixes" the numbers so that they can be properly compared by ensuring that the last few significant digits are rounded.
I might add an argument to %round in the future to specify the number of decimal places to round to. |
|
|
|
shalimar GURU
Joined: 04 Aug 2002 Posts: 4691 Location: Pensacola, FL, USA
|
Posted: Fri Mar 04, 2011 8:27 am |
I actually tried throwing in a ,2 when testing it out, just to see if that was an undocumented feature. That would be a quite useful addition.
|
|
_________________ Discord: Shalimarwildcat |
|
|
|
|
|