Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / ValFloat() and floating point errors

Author
Message
Velector
11
Years of Service
User Offline
Joined: 8th Jan 2013
Location:
Posted: 12th May 2013 02:01
Hello all,

I am working on something in Tier 1 for a client that involves the user to click a bunch of VirtualButtons to create a string of numbers (imagine a calculator). The numbers can be any number from 0 to 9999.99. I achieve this by appending the clicked number to a string.

Example:
Click 1 -> current_number$ = current_number$ + "1"
Click 2 -> current_number$ = current_number$ + "2"
Click decimal, then click 3 -> current_number$ = current_number$ + "." + "3"

...and so on.

This works and displays rather beautifully, until I need to store the number as a float for later processing.

I have checks in place to determine whether the input exceeded two decimal places (and limiting the number of times the decimal button can be pressed) to prevent conversion errors.

I first tried the Val() function, and got an integer output. After double checking the documentation, I found ValFloat(). This seemed simple and straightforward enough. I compiled, ran, input my test data, and everything seemed to be correct up until I went into the triple digits.

Input 1.50 outputs 1.500000
Input 6.66 outputs 6.660000
Input 666.66 outputs 666.659973

I thought maybe there was an error in my code, so I put a few Message() statements in to try to trap it. Completely bypassing input, I tried:


and got the output, 666.66


and got the output, 0.000000


and got the output, 666.659973


and got the same output as above.

I did a bit of searching on these forums, and found a few string to float conversion functions that worked for others prior to the ValFloat() function being officially in AGK. As a shot in the dark, I tried those, and get the same botched number output, so I am wondering if this is a floating point computation error on AGK's part, at the core level. I am pretty sure it is not a floating point issue at the processor level on my end, as it is an Intel i3. It is an older processor (a few years old), but it is modern enough that there shouldn't be any floating point precision errors like Intel and AMD had in the early days (if anyone remembers those...)

This has me absolutely stumped. I am currently running AppGameKit 108 Beta 11 on Windows 7 Home Premium x64. Or at least I think I am running 108. I downloaded 108 the installer from my products page, but the about box still says Build 107. I uninstalled 107 completely prior to installing 108. My only other testing machine cannot run AppGameKit (older netbook, WinXP).

Any ideas on as to why this is happening, or a way I can achieve the same function without concatenating a string then type converting to a float, would be much appreciated.

Thanks for taking the time to read this post. If I have missed anything, please feel free to ask.
Markus
Valued Member
20
Years of Service
User Offline
Joined: 10th Apr 2004
Location: Germany
Posted: 12th May 2013 09:30
i think the str show different.
JimHawkins
15
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 12th May 2013 11:10
I tried this in Delphi and got the same result with single floating point numbers. The float type in AppGameKit Basic is a single, unfortunately. This may well be because ARM < V7 has no FPU.

Likewise there is no 64-bit integer or unsigned type.

This does not happen with doubles.

I think it's because for calculation the numbers are converted to doubles and then back to a single for output, and forcing a double or extended type to single causes floating point rounding errors.

Unless you want to do maths on the numbers I would suggest using two integers - one for the mantissa and one for the fraction.

Type MyDouble
mantissa
fraction
endtype

These kinds of limitation are another good argument to move to C++ or Pascal!

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 12th May 2013 12:25
I guess the question is how accurate you want to get and what exactly is the "function" you are trying to perform?

Does the result need to be rounded to 2 decimals?


this.mess = abs(sin(times#))
Digital Awakening
AGK Developer
22
Years of Service
User Offline
Joined: 27th Aug 2002
Location: Sweden
Posted: 12th May 2013 13:39
You can code around this using an integer instead. You just need to include the decimal point when displaying the value. So 9.99 is stored as 999 in an integer. Simply add 00 at the end of whole numbers: 9 = 900, 9.9 = 990.

JimHawkins
15
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 12th May 2013 14:24
True - the maximum number for 2 digits of the fraction would be:

21474836.99

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
Velector
11
Years of Service
User Offline
Joined: 8th Jan 2013
Location:
Posted: 12th May 2013 14:36
Hi all,

Thanks for the replies. To cover most of the questions (I am mobile on netbook, so no access to AGK), I will definitely be doing calculations on these numbers. We are playing around with the idea of a market system, with the "government" taxing each transaction, by region. Its similar to the Auction House in World of Warcraft, which is why I have users clicking buttons to input numbers, rather than trusting them to validate input using their keyboard. It also looks nicer and more "polished" on mobile platforms.

If I go with Digital Awakening's suggestion, an object valued at 9.00 PKD (in-game currency) and a 25% transaction fee would compute like this:

900 * 25 = 22500
100 * 100 = 10000 (the division factor)
22500 / 10000 = 2.25

25% of 9 PKD is 2.25 PKD if I use a calculator, so the math checks out. I do need the final number rounded to two decimal places, to the nearest whole cent.

Example:
925 * 25 = 23125
100 * 100 = 10000
23125 / 10000 = 2.3125

2.3125 -> 2.32

I assume I could do the rounding by tokenising the number after the decimal, and put a decimal in there after the 2nd digit, then using AGK's Round() function to get the nearest whole number, and use that for the fraction.

After that, it should just be a case of adding the two for the amount taken from the purchaser, and only give the seller the 9 PKD.

9 + 2.25 = 11.25 billed to the purchaser
9 given to the seller
2.25 given back to the "system."

I am worried I will end up running into the same issue as my original post when displaying the amount to bill to the purchaser. The display would be done like this:



And I assume it would output 11.25 PKD, but if I have something like 666.66 it will place me back at square one. I'll have to try that out when I get to my workstation.

Hope this helps. Thanks again for all suggestions and responses. I'll be back later tonight, or sometime tomorrow with results of the rounding.
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 12th May 2013 23:05
That makes it much easier. If everything can be calculated in "cents" then do it ALL that way and add the decimal back in afterwards. Simple.

Another thing you might find handy is the optional parameter in the str() function.

If you have a float:
myFloat# = 666.66

You can turn it into a string using a number of decimals allowed:
myString$ = str(myFloat#, 2)


this.mess = abs(sin(times#))
Velector
11
Years of Service
User Offline
Joined: 8th Jan 2013
Location:
Posted: 13th May 2013 01:36
If my previous post posted twice, please disregard. The page refreshed when I clicked on the recently closed tab in Chrome. It may have because I got the post submit confirmation at the top of the page.

@baxslash, the decimal parameter on the str() function is the first time I am hearing of this. For fun, I decided to try it out with my demo code, and it resolved the issue, even the rounding error. I did not have to change anything except for adding the decimal parameter as you suggested.

I ran demo calculations with a bunch of test scenarios, comparing with a real calculator, and the results are identical. I've decided that I will be setting the input cap at 9999.99 PKD. Anything over that is overkill and will simply destroy the economy. (If only real life worked that way...)

Problem solved. If I run into errors in the future, I'll switch to using whole numbers and do the division as stated in my previous post.

Thank you all who have helped. Have a great day/night!
Marl
13
Years of Service
User Offline
Joined: 19th Nov 2011
Location: Bradford, UK
Posted: 13th May 2013 20:14
Quote: "If everything can be calculated in "cents" then do it ALL that way and add the decimal back in afterwards. Simple."

Or Don't convert at all, simply slip in the dot as you display it.

The standard advice for this is "Financial transactions should always be calculated with integers".

Despite what you might think, no financial institution in the world uses floating point - it's simply not accurate enough.

So as Baxslash says, work it out in pence / cents.

Rather than;

900 * 25 = 22500
100 * 100 = 10000 (the division factor)
22500 / 10000 = 2.25

( Since 25% is also 1/4 ), You can simply have;

900 / 4 = 225

then output it with a bit of jiggery pokery;

Login to post a reply

Server time is: 2024-11-24 15:12:09
Your offset time is: 2024-11-24 15:12:09