Porting C program to Access VBA (floating point issues)

C

Curbie

I'm porting a C program to Access (VBA) and I'm running into some
slight floating point errors, nothing real big, but given enough FP
math they can add up and on some data there is a lot FP math.

The C program runs fine in a C environment (Dev-C++) on my system so
it can't be differences in floating point co-processors.

Does anyone have some experience with porting C floating point over to
VBA?

I need some help, hints, tips and a cocktail.

Thanks,

Curbie
 
A

Albert D. Kallal

I'm porting a C program to Access (VBA) and I'm running into some
slight floating point errors, nothing real big, but given enough FP
math they can add up and on some data there is a lot FP math.

The C program runs fine in a C environment (Dev-C++) on my system so
it can't be differences in floating point co-processors.

Does anyone have some experience with porting C floating point over to
VBA?

I need some help, hints, tips and a cocktail.

Thanks,

Curbie

Well, keep in mind that floating point numbers are always an approximation.
Thus, in ms-access we have:

Public Sub TestAdd()
Dim MyNumber As Single
Dim i As Integer

For i = 1 To 10
MyNumber = MyNumber + 1.01
Debug.Print MyNumber
Next i
End Sub

Here is the actual output of the above:

1.01
2.02
3.03
4.04
5.05
6.06
7.070001
8.080001
9.090001
10.1

You can see that after just 7 additions..already rounding is occurring

And if we add the following line of code to the end of the above:


if MyNumber = 10.1 = True then
msgbox "the number is 10.1"
else
msgbox "the number is something else"
endif


The above will produce:

the number is something else

In other words, the number displayed is NOT 10.1

Doing the same in c++, we get:

//

#include "stdafx.h"

int main(int argc, char* argv[])
{
int i;
float MyNumber = 0;

for (i = 1; i <= 10;++i)
{
MyNumber = MyNumber + 1.01F;
printf ("%f\n", MyNumber);
}

return 0;
}

Output is:

1.010000
2.020000
3.030000
4.040000
5.050000
6.060000
7.070000
8.080001
9.090001
10.100001

Again, you can see the "final" result is NOT 10.1

So, the above is very much near day 1 in any computing science class. Simply
put, decimal representation in a computer are only *approximate* for decimal
numbers. You really can't use decimal numbers in comparisons.

If you need more precision in VBA, use double in place of single...you jump
to 8 bytes, and you should not get much difference in rounding then what you
had going on in your c code.

However:
I would suggest that if you have a fixed number of decimal places (say up to
4), then use the currency data type in VBA. Currency is a scaled integer
value and will not round numbers on you! It is ideal for payroll and the
many business applications that ms-access is typically used for.

It also not clear if you trying to avoid rounding, or you want the "exact"
same rounding in VBA as in your c code? I really do not know the answer for
this. I assume they both use IEEE formats. However, I can be sure that
rounding and results will be 100% identical with c++ code vs that of VBA
code.

so, try bumping up the precision (size) from single to double in VBA. That
should give you ample head room in terms of rounding errors.

And, if you need MORE then 4 decimal places without any rounding then you
can use a scaled integer (packed decimal) in VBA. Scaled integers very cool
and they allow up to about 28 signification digits with NO rounding at all.
So, "Decimal" type in VBA are simply really big integer values with a
'scale' option to place the decimal point into that big integer as a
position.

You might want to expand a bit on what your rounding problem here is.
Usually for financial stuff, we use the currency data type, but I suggest
you use "double" in place of "single" for starts if you need floating types.
However, if this is financial data, then we back to the 1st day of computing
science.....and you have to watch out for rounding errors as both my c++ and
VBA examples show just have a few addtions...things go wonky...
 
A

Albert D. Kallal

I can be sure that
rounding and results will be 100% identical with c++ code vs that of VBA
code.

should read:

I can NOT be sure that......
 
C

Curbie

Albert,

Thanks for the reply!

The program I've ported is published be the National Renewable Energy
Libratory (NREL) called "pvwatts.c" (photo-voltaic watts) and is used
by NREL to estimate solar radiation incident on fixed, 1-axis, or
2-axis photo-voltaic panels or (surfaces).

It's packed with float (single) variables, and gets its input from
Typical Metrological Year v.2 (TMY2) database that contains a year's
worth of measured weather data from 239 reporting stations scattered
around the U.S., recorded on an hourly basis. So, between the rounding
errors that occur between various functions that make up Pv-Watts and
summarizing daily, monthly, or yearly data, the totals are creeping
away from the results published by NREL.

My plan is to port Pv-Watts to MS-Access to create yearly/monthly data
summaries of TMY solar radiation for thermal heat-gain/loss
calculations for houses, calculations for solar thermal heating panels
as well as PV panels, the summaries to be used in the location tab in
an Alternative-Energy spread-sheet, to compare natural alternative
energy resources of the different TMY 2 (239) or 3 (1020) reporting
stations.

I chose Pv-Watts so I could verify my porting efforts against data
results published by NREL before tweaking Pv-Watts's output for the
data I need.

If I interpret your reply correctly do you think I should replace
troubling singles with doubles, I don't need exact results, just
accurate results for verification? After the complex math dance is
done, the basic results is just a few watts or BTU per ^2.

Thanks for your time and help.

Curbie
 
A

Albert D. Kallal

Curbie said:
If I interpret your reply correctly do you think I should replace
troubling singles with doubles, I don't need exact results, just
accurate results for verification? After the complex math dance is
done, the basic results is just a few watts or BTU per ^2.

Yes, the above is likely a reasonable assumption and should give your more
then amble precision here.

Hence, if you want roughly the same precision as the c program then using
doubles in the above code should do the trick for you. However, as I
mentioned, if you doing any type of financial calculations (for money or
accounting systems), then you cannot use floating point numbers in your
application since then your never be able to balance your accounts. (that
1st day of computing class again!!). It just that computers do not accurate
represent floating point numbers.

So, if your "data" being stored in tables NEVER has more then 4 decimal
points, then use the currency data type to store/hold the data + results in
tables. It is not 100% clear if you taking about the data storage here, or
simply your code that doing calculations

.. Anyway, yes...you get very similar rounding (if not the same) as your c
program if you use double vars in your code. The only "issue" left here is
choosing the correct data type for the tables if they are storing the
results of this calculation stuff. As mentioned, if you source data (or
results) don't need/have more then 4 decimal places, then use currency data
type. As then you can use the report writer to total, summarize, and do some
reporting on that data without any rounding errors at all. (since currency
is not a floating point number, but is a scaled integer).
 
C

Curbie

Albert,

Thanks for all your time and help, I greatly appreciate it!

Debugging just should far less frustrating knowing when dealing with
FP results I'm evaluating approximates I.E. "don't sweat the small
stuff" which I normally do, and has been driving me nuts chasing my
(de) tail.

Curbie
 
T

Tony Toews [MVP]

Curbie said:
Debugging just should far less frustrating knowing when dealing with
FP results I'm evaluating approximates I.E. "don't sweat the small
stuff" which I normally do, and has been driving me nuts chasing my
(de) tail.

Trouble is that, in some circumstances, cumulative errors can make a
huge difference. Such as a loop multiplying numbers.

Tony
 
C

Curbie

Trouble is that, in some circumstances, cumulative errors can make a
huge difference. Such as a loop multiplying numbers.
Tony,

I've already run into that, there seems to be rounding errors any time
access call an VBA function typed as "Double" with a single as an
input value. I think Albert's suggestion will help there, although the
C program doesn't compare FP values to 0 it does greater and less than
comparison along with some Mod and other things that can be affected
by precession. Like:

359.46 Mod 360 = 359
359.52 Mod 360 = 0

The bottom line is I made good progress today narrowing the
differences on some output and determining the differences for other
output MUST be porting problems I caused.

All in all Albert's explanation and suggestions have been very
valuable, it is just so counter-intuitive NOT to pay attention to
detail.

Thanks,

Curbie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top