ValD() StrD(X$,2) are killing me

Just starting out? Need help? Post your questions and find answers here.
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

ValD() StrD(X$,2) are killing me

Post by Rook Zimbabwe »

OK is ther eany way to use this without rounding UP?

I have to keep the pricing in my database consistent with idiot pricing policy. People want you to pay 9.99 for something instead of 10.00...

I know... that extra penny would break you!

When I retrieve my prices from the database they have extra numbers past the decimal that aren't there in reality.

I had to change my program from my old way.

I have to use the CURRENCY value of those coluumns in the database or the reports in the database do not work.

the value is reported to the program as 9.9900 and not 9.99

the program calls it 10.00
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

You are assigning it to a float aren't you?

Code: Select all

b.s="9.9900"
a.d=ValD(b)
Debug StrD(a,2)

c=ValD(b)
Debug StrD(c,2)
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

Rook Zimbabwe, I think using binary floats in financial applications is risky, I would recommend using decimal.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

ValD() StrD(X$,2) are killing me
Vald means violence (!): http://www.dokpro.uio.no/perl/ordboksoe ... n&renset=j

You shouldn't use floats/doubles for money (but it's a problem as you haven't got anything else!)
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

you could use the VB6 runtime DLL's, the one with decimal functions is oleaut32.dll or you could use DecNumber which has more functionallity, BTW, I translated some of the headers from DecNumber and tested the lib compiled with PellesC OK, I used the package from the GNU GCC compiler, as it's licence has the exception clause allowing you to static link the lib into your app without the app falling under the GPL license.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

I think the easiest way to deal with money is to input as a string, convert the input to the pounds or dollars times 100 + pence/cents. Work with that and then convert the output back by integer dividing for the pounds/dollars and the remainder for pence/cents. That way it is all integers and no spurious bits creep in.
Mike.
(I'm never going to catch up with the improvements to this program)
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Post by citystate »

I'd use Longs, but store the value in cents
so

100 = $1.00
999 = $9.99

no precision errors that way
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

you would still have to keep track of the implied decimal point if you do any math operations and adjust them to keep the 2 decimals as you suggested
for example, let's say you have n = 1234 with 2 decimals (12.34)
if you multiply n*n as integers you have 1522756 (result is 152.2756)
similarly if you add two numbers and you have a carry over.
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Post by citystate »

I can't think of an instance where you'd multiply two currency values together though

there'd be no problem at all with addition - even with a carry-over

999 ($9.99) + 2 ($0.02) = 1001 ($10.01)
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

yes your right.
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

citystate wrote:I can't think of an instance where you'd multiply two currency values together though
There are cases though were two values are multiplied, eg $11.25 * 0.1 for ten percent tax.

But you can track it, as jack pointed out.


I went through all this zillions of years ago with dos and QBasic. In the long run using reals is easier and pretty darn accurate. More accurate in some cases.

The tiny differentials need a humongous amount of calcs and huge values to become significant at the cents level.

Generally, the only time the values need to be trimmed or fixed are for display purposes, or for rounding fractions when you do something like the tax calc above. And you would need to round that anyhow.

Thus: 1125 x 10 ($11.25 * 0.10) = 11250 with 4 decimal places, eg 1.125

Now you make your rounding decision. Except you are using integers instead of floats and you are also having to keep track of decimal places.

Also, if you use integers, you will need to buffer for times when you divide. Otherwise bits fall off:

Code: Select all

vA.l = 1125
vB.l = 10
vC = vA / vB
Debug vC
Now we need to keep track of the bits that fall off. :) Or pad so we store $11.25 as 112500 (or however many decimal places of a cent you think is needed).

I truly believe you are better off staying with doubles and just adjusting when it is absolutely necessary. I do believe that once you get into any * / math you are going to create greater inaccuracies with integers.
Dare2 cut down to size
superadnim
Enthusiast
Enthusiast
Posts: 480
Joined: Thu Jul 27, 2006 4:06 am

Post by superadnim »

Could you adapt it to something like this? (string based)

Code: Select all

Structure Money
	bucks.l
	cents.l
EndStructure

Macro MoneySetString(_handle_, _str_)
	_handle_\bucks 	= Val(_str_)
	_handle_\cents 	= Val(StringField(_str_,2, ","))
EndMacro

Macro MoneyGetString(_handle_)
	Str(_handle_\bucks) + "," + Str(_handle_\cents)
EndMacro

;- Test
Define.Money test
MoneySetString(test, "89,99")
Debug MoneyGetString(test)
It's not as fast as handling floats but it'll be secure in comparison.


But, anyway what's wrong with this? It returns correctly here:

Code: Select all

money.f = 89.99
Debug StrF(money, 2)
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

seriously, using binary floats/doubles for financial apps is a bad idea, $0.01 X 1000,000 adds up to a significant amount.
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

The QBasic app I mentioned above handled lending portfolio's for financiers and small commercial banks. It passed all the legal requirements on a heavily governed industry. It used doubles (14 digits of accuracy, 15 sometimes claimed).

Code: Select all

my.d = 123456789012.34
Debug my
Admittedly, none of the users operated in the tens of billions, but it coped.

Doubles should be safe for a restaurant POS system and if the prices are that high that it cannot cope then I am not eating there! :)

In the absence of a currency type and good math to handle it, floating point seems safer than integer to me.

I can't see the actual problem here. However I am probably missing something so I stand to be corrected and educated. :)
Dare2 cut down to size
Post Reply