money format

New to FreeBASIC? Post your questions here.
Post Reply
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

money format

Post by BasicCoder2 »

When I divide by 100 why do I sometimes get more than two digits after the decimal point?

Code: Select all

dim as integer money
for i as integer = 0 to 20
    money = int(rnd(1)*100000)/100  'create a random amount in cents
    print money/100  'show it as dollars
next i
sleep
Muttonhead
Posts: 139
Joined: May 28, 2009 20:07

Re: money format

Post by Muttonhead »

i think the term "money/100" is a float and has its well-known typical precision and rounding problems
may be I am wrong

edit...

edit2:
dodicat provides a rounding function too, ...so I trust myself again

Code: Select all

'inspired by http://www.dreael.ch/Deutsch/BASIC-Knowhow-Ecke/Gleitkommazahlen.html
'a 2 digit behind point rounding function
function Float2String(value as double) as string
  function="0"
  dim as integer l
  dim as string vstring,newstring
  vstring = str(int(100! * abs(value) + .5))
  l=len(vstring)
  if l=1 then newstring ="0.0" & vstring
  if l=2 then newstring ="0." & vstring
  if l>2 then newstring =left(vstring,l-2) & "." & right(vstring,2)
  'if right(newstring,3)=".00" then newstring=left(newstring,len(newstring)-3)'
  if sgn(value)=-1 then newstring ="-" & newstring
  function=newstring
end function

dim as integer money
for i as integer = 0 to 20
    money = int(rnd(1)*100000)/100  'create a random amount in cents
    print money, money/100, float2string(money/100)  'show it as dollars
next i
sleep
Mutton
Last edited by Muttonhead on Jul 24, 2015 14:24, edited 3 times in total.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: money format

Post by fxm »

If it's just a displaying problem, you can use this simple workaround (working for values of any size and any sign):

Code: Select all

dim as integer money
for i as integer = 0 to 20
    money = int(rnd(1)*100000)/100  'create a random amount in cents
    dim as double m = money/100
    dim as integer s = sgn(m)
    print s*int(s*m); using ".##"; s*m - int(s*m)
next i
sleep
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: money format

Post by dodicat »

The float representation is not good.

Code: Select all

#include "crt.bi"
print 9.70
printf("%f",9.70)
sleep
 
Using C again, perhaps a dedicated Rounding function:

Code: Select all

 #include "crt.bi"
 
function CRound(byval x as double,byval precision as integer=2) as string
    if precision>30 then precision=30
    dim as zstring * 40 z:var s="%." &str(abs(precision)) &"f"
    sprintf(z,s,x)
    var ans = rtrim(rtrim(z,"0"),"."),zeros="",i=instr(ans,".")
    if i then zeros= string(precision-(len(ans)-i),"0")
    return ans+zeros
end function 

dim as integer money
for i as integer = 0 to 20
    money = int(rnd(1)*100000)/100  'create a random amount in cents
    print cround(money/100),money/100  'show it as dollars
next i
sleep
  
P.S.
The C function will use banker's rounding.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: money format

Post by MrSwiss »

dodicat wrote:The C function will use banker's rounding.
What exactly does that mean? A new sinister way to rip us all off?
(That's what bankers usually do, all day long ;-) , except of course, earning far too much money.)
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: money format

Post by marcov »

MrSwiss wrote:
dodicat wrote:The C function will use banker's rounding.
What exactly does that mean? A new sinister way to rip us all off?
(That's what bankers usually do, all day long ;-) , except of course, earning far too much money.)
Questions about Bankers from sb named "MrSwiss" ? :-)

Actually it is fairly simple. If you have a value with n digits behind the comma, the number of non integer values between two whole numbers is 10^n-1 which is odd.

This means that normal, scientific, rounding incurs a bias (4 digits, 1-4 down, 5 digits, 5-9 up), or with two digits .01-.49 down, .50-.99 up.

Bankers rounding simple fixes that bias by rounding .5(0) up one way for even numbers, and the other for odd numbers.

As to the subject, currency calculations are generally done in currency types with special formatting routines that format scaled integers or BCD types directly to decimal representation, without calculating binary value first.
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: money format

Post by marcov »

dodicat wrote:The float representation is not good.

dim as integer money
for i as integer = 0 to 20
money = int(rnd(1)*100000)/100 'create a random amount in cents
print cround(money/100),money/100 'show it as dollars
next i
sleep
[/code]
P.S.
The C function will use banker's rounding.
The routine does, but the code before (that I quoted) already rounds a decimal number to a binary floating point. The same goes for the formating routine sprintf that uses binary floats internally.

Is there no BCD or scaled integer support in the std C lib ? Windows has the "currency" type (scaled int by 10000 iirc) for this.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: money format

Post by MrSwiss »

marcov wrote:Questions about Bankers from sb named "MrSwiss" ? :-)
Well, as you might know:
not everybody in Holland/Netherlands is able to make "Edammer Cheese", grow Flowers etc.
The same applies to Switzerland ... :-D
we have, apart from Banks/Bankers: Insurances, Industry, Pharma, Choccolat, Cheese, Fondue ... even some coders,
amongst a lot of other jobs.

The question was meant to be a joke ... more than anything else.

Thanks for the detailed answer anyway!
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: money format

Post by marcov »

MrSwiss wrote:
marcov wrote:Questions about Bankers from sb named "MrSwiss" ? :-)
Well, as you might know:
not everybody in Holland/Netherlands
I'm from the Netherlands, but not from Holland. There is an huge difference. Unfortunately can't say too loud, since that would be a bit pot and kettle, coming from a region where all German speaking people are routinely referred to as "Prüsse"
is able to make "Edammer Cheese", grow Flowers etc.
Since I'm not from Edam, but from Limburg, so I OBVIOUSLY make Limburger cheese :-) (mainly between the toes though)

As to growing flowers, weeds also flower.
The question was meant to be a joke ... more than anything else.
I wasn't too seriously either, neither in this message. Unfortunately it is all true though :-)
Thanks for the detailed answer anyway!
I forgot to mention the main reason for why one would try to avoid (binary) floating point for monetary amounts at all costs:

Sooner or later in your IT career you will be in a situation where you bill your customers, and then you'll have to deal with accountants. Accountants are strange folk, and they can really be obsessed endlessly about a discrepancy of a few cents in their balances.

Worse, they can ruin your perfectly fine after hours drink in the pub by jabbering on about it endlessly!
Last edited by marcov on Jul 26, 2015 8:45, edited 1 time in total.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: money format

Post by MrSwiss »

marcov wrote:Sooner or later in your IT career you will be in a situation where you bill your customers, and then you'll have to deal with accountants. Accountants are strange folk, and they can really be obsessed endlessly about a discrepancy of a few cents in their balances.

Worse, they can ruin your perfectly fine after hours drink in the pub, by jabbering on about it endlessly!
I've had my first encounter with accountants before even starting with anything IT related (as a Field-Technician for some machinery).
However, they've never been able to ruin a pub session, because they where always left to complain about anything, alone.

But thanks for the warning! It definitely has it's merit.
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: money format

Post by jevans4949 »

Typically, financial applications should hold monetary amounts in cents, to preserve accuracy. When you need to print them, use the STR function to covert, then edit to put in the necessary leading zeros and decimal point.

If calculating sales tax, or interest, make sure you follow any local rules for rounding. If there are none, use floating-point and reduce to integer cents.

The problem with binary floating-point variables is that they cannot totally represent any fraction where the denominator is not a power of two, i.e 1/2, n/4, n/8, n/16, n/32. Decimal 0.5, 0.25, 0.125, or any sum of them, are OK, but 0.01 will not be.

For much the same reason, simple decimal calculators cannot accurately represent, e.g., 1/7. More sophisticated calculators get round that by holding the result of divisions internally as improper fractions as long as possible. To check out your calcultor, try 1 / 7 * 7. Do you get 1 or 0.9999999?
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: money format

Post by BasicCoder2 »

@jevans4949,
Exactly what I suspected but I wasn't sure. I was keeping the value as cents as an integer.
With all our physical exchanges money has to be rounded to 5 cents although with electronic transactions they are kept exactly to the cent. So if I buy a product with cash for $5.62 I gain 2 cents. If I buy it with cash for $5.63 I lose 2 cents.

Code: Select all

dim as integer money
dim as string  strMoney
money = 45
strMoney = str(money)
print left(strMoney,len(strMoney)-2);".";right(strMoney,2)
sleep
Last edited by BasicCoder2 on Jul 25, 2015 22:55, edited 1 time in total.
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: money format

Post by jevans4949 »

Years ago I worked on a currency exchange application in New York where rates were quoted with a variable number of decimal places followed by a fraction with a denominator in up to 64ths, e.g., 1.325 and 17/32. (=1.32553125) AFAIR we just converted it to 8 decimal places to do the actual calculation. Fun!

Prior to 1971, in Britain we had to cope with 12 pence make one shilling, and 20 shillings make 1 pound. in that case we held pounds as a signed integer and pence as a ubyte; one penny overdrawn was thus -1 pound + 239 pence. Interest (positive or negative) was then easily calculated on whole pounds.

The system for calculating daily interest to be applied quarterly was to accumulate the balance of the account multiplied by the number of days since it last changed. On interest calculation day, multiply by the interest rate and divide by 365. (In Germany, practice was - probably still is - to divide by 360.)
Post Reply