At present, in my Decimal Plugin, the Decimal type can be converted to  
the Double type, and vice versa. So when a Decimal variable is equated  
to a Currency variable, RB converts the Currency variable to a Double  
and then my plugin converts the Double to a Decimal. The Double type  
also intermediates when a Currency variable is set equal to a Decimal  
variable. This may be "good enough", but it is not a perfect solution.

It's not perfect because the Currency variable is really an Int64 with  
an assumed decimal point giving 4 places to the right of the decimal  
point. The largest positive number that fits into an Int64 is 2^63 - 1  
= 9,223,372,036,854,775,807 which has 19 significant figures, so the  
largest currency value is 922,337,203,685,477.5807. But the largest  
mantissa (ignoring decimal point and exponent) in an 8 byte double is  
2^53 = 9,007,199,254,740,992. That has 16 significant figures, so it  
lacks about 3 significant figures from the highest currency value. So  
not all currency values fit into a double.

So in my Decimal Plugin, with Xcode, I created a function which took  
an Int64 (as a long long) and converted that to a Decimal with 4  
digits after the decimal point. I'm using GMP for the multi-precision  
library. Here's the simple source:

// get dec from currency (treated as INT64 x 10^-4)
void getDec_Curr(DecData& z, long long& x)
{
        bool            isNegative;
        long long       xx;
        
        xx = x;
        
        if(xx<0)
        {
                isNegative = true;
                xx = -xx;
        }
        else
                isNegative = false;
        
        z.i = (unsigned long int)xx;
        z.e = -4;
        
        if(isNegative)
                z.i = -z.i;
        
        normalize(z);
        
}/* getDec_Curr */

Note that I call the Int64 by reference. I also tried calling by value  
with the same results given below.

In DecimalPlugin.cpp I have the function:

static REALobject convertCurrToDec(long long& x)
  {
         REALobject                     z;
         DecData                        *zData;
        
         z = REALnewInstance("Decimal");
         zData = (DecData *) REALGetClassData(z, &DecClass);
        
         getDec_Curr(*zData, x);
        
         return z;

  }/* convertCurrToDec */

and the other methods definition:

{ (REALproc) convertCurrToDec, REALnoImplementation,  
"DecimalFromCurrency(ByRef x As Currency) As Decimal" }

The revised plugin built with no errors. A simple RB program for  
testing has a PushButton with source:

   Dim z As Decimal
   Dim c As Currency // holds 15 digits to left of decimal point and 4  
digits to the right
   DecSetScale(4)
   c = CDbl(EditFieldx.text)
   z = DecimalFromCurrency(c)
   EditFieldz.text = str(z)

One finds the results:

Input c = 1.2345
Output x = 1.2345

c = -1.2345
x = -1.2345

c = 12345.6789
x = 12345.6789

c = 123456.7891
x = 123456.7891

c = 1234567.8912
x = 375574.4320  problem!

After a lot of experimenting, I found the solution to the problem. RB  
is incorrectly passing only the lower 32 bits of a 64 bit currency  
number to the plugin. To verify this, one inputs the currency number  
2^32/10^4 = 429496.7296:

c = 429496.7296
x = 0.0000

Then adding anything below 2^32/10^4 to 429496.7296 should give that  
added number in x:

c = 429496.7296 + 123456.7891 = 552953.5187
x = 123456.7891

And 2*2^32/10^4 should again give a zero for x:

c = 858993.4592
x = 0.0000

and so on.

Then I changed Currency to Int64 in the definition:

{ (REALproc) convertCurrToDec, REALnoImplementation,  
"DecimalFromCurrency(ByRef x As Int64) As Decimal" }

and used the RB program:

   Dim z As Decimal
   Dim c As Int64
   DecSetScale(4)
   c = CDbl(EditFieldx.text)
   z = DecimalFromCurrency(c)
   EditFieldz.text = str(z)

so now:

c = 12345 (no decimal point!)
x = 1.2345 (I didn't change convertCurrToDec so the decimal point is ok)

and so on. But for 2^32 input:

c = 4294967296
x = 0.0000

So the same problem exists for an Int64 value. RB incorrectly passes  
only the lower 32 bits of the Int64 value to a plugin. I haven't  
tested a UInt 64, but my guess is that value won't be passed correctly  
either.

I think this is a bug in RB 2007 R5.

Bob


_______________________________________________
Unsubscribe or switch delivery mode:
<http://www.realsoftware.com/support/listmanager/>

Search the archives:
<http://support.realsoftware.com/listarchives/lists.html>

Reply via email to