Pages:
Author

Topic: why JSON RPC values not use INT64 instead of float string? - page 4. (Read 18438 times)

legendary
Activity: 1232
Merit: 1076
You're right. In that case, it seems that going with strings is the only option.

All serious institutions (like banks) never use floats for currency calculations because they know the dangers.
If we want to be seen as "serious", float is not an option.

Yep but it's a problem with the json decoding in PHP/Perl/Python. The actual precision for the number in a JSON is accurate AFAIK.
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
You're right. In that case, it seems that going with strings is the only option.

All serious institutions (like banks) never use floats for currency calculations because they know the dangers.
If we want to be seen as "serious", float is not an option.
legendary
Activity: 1232
Merit: 1076
You're right. In that case, it seems that going with strings is the only option.

Still it might be a good idea to have API versions (bitcoin.getinfo()["rpcversion"]) and take an optional -rpcversion command line argument. When you create a new API, then the old one is deprecated for at least one release cycle, allowing compatibility.

When a new RPC version is created (lets call new version 1 and old version 0 for example) then:

bitcoind
The RPC version (0) in this release is DEPRECATED! Re-run bitcoind -rpcversion=1 for the new version. RPC changes can be found at http://bitcoin.org/rpcapi.html
bitcoind stop
bitcoind -rpcversion=1
bitcoind getinfo
...
"rpcversion": 1
...

The policy would be to deprecate only when the API becomes backwards incompatible. Otherwise it's silently upgraded and becomes the default.
legendary
Activity: 1652
Merit: 2311
Chief Scientist
Then we can make nAPIVersion 0.5 supporting the int64 with appended .0 as luke-jr has done in his gitorious branch.

That's just dumb.

If the problem is jsonrpc-supporting-environments that don't support double-precision floats, then multiplying and slapping a zero on the end won't fix the problem-- you'll just either lose precision as it gets squeezed into a 32-bit float or get a 32-bit-integer-overflow error.

legendary
Activity: 1232
Merit: 1076
Code:
$json '{"a":1,"b":2,"c":3,"d":4.08,"e":5}';
var_dump(json_decode($json));
?>


Output:

Code:
object(stdClass)#1 (5) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ["d"]=> float(4.08) ["e"]=> int(5) }

Why don't why put in a new number like

nAPIVersion and call the current API 0.

Then we can make nAPIVersion 0.5 supporting the int64 with appended .0 as luke-jr has done in his gitorious branch.

Then I want to make an API version 1.0 which puts in a strict naming convention for the methods (getblaa, action instead of the current messy names) and use namespaces.
legendary
Activity: 1652
Merit: 2311
Chief Scientist
Is there a PHP implementation that does not use double-precision floating point?
After doing a little googling I couldn't figure out the answer to that.  I will be MUCH more sympathetic to changing the JSON-RPC api if there is.

And mizerydearia:  re: the witcoin issue:  You say:
"I see the transaction as 0.94 However, http://json-rpc.org/ retrieves the data as 0.93999999999999994671"

So why when you display that value are you truncating it instead of rounding it to 8 decimal places?
For example:
Quote
> php -r "printf('%.8f', 0.94);"    #CORRECT
0.94000000
> php -r "printf('%.16f', 0.94);"   #WRONG
0.9399999999999999

... or to convert to an integer-number-of-base-unit:
Quote
> php -r '$val=0.94; printf("%d", round(1e8*$val));'
94000000

All of that assume that your php support double-precision floating point, which brings me back to my question:  are there any php implementations that do not?
legendary
Activity: 1232
Merit: 1076
Anyone that prefers a saner API (because they're using PHP) should check out my branch,
https://github.com/genjix/bitcoin/tree/strrpc

Values are returned as int64 strings.
Code:
function numstr_to_internal($numstr)
{
    return bcmul($numstr, pow(10, 8), 0);
}
function internal_to_numstr($num, $precision=8)
{
    $repr = gmp_strval($num);
    $repr = bcdiv($repr, pow(10, 8), $precision);
    # now tidy output...
    # trim trailing 0s
    $repr = rtrim($repr, '0');
    # and a trailing . if it exists
    $repr = rtrim($repr, '.');
    return $repr;
}

Those are the 2 functions I use to convert from internal values to display/user input values (numstr).

I updated the wiki, https://en.bitcoin.it/wiki/API_tutorial_%28JSON-RPC%29#PHP
legendary
Activity: 1232
Merit: 1076
Code:
import urllib
import decimal
import json

class JSONRPCException(Exception):
    def __init__(self, rpcError):
        Exception.__init__(self)
        self.error = rpcError
       
class ServiceProxy(object):
    def __init__(self, serviceURL, serviceName=None):
        self.__serviceURL = serviceURL
        self.__serviceName = serviceName

    def __getattr__(self, name):
        if self.__serviceName != None:
            name = "%s.%s" % (self.__serviceName, name)
        return ServiceProxy(self.__serviceURL, name)

    def __call__(self, *args):
         postdata = json.dumps({"method": self.__serviceName, 'params': args, 'id':'jsonrpc'})
         respdata = urllib.urlopen(self.__serviceURL, postdata).read()
         resp = json.loads(respdata, parse_float=decimal.Decimal)
         if resp['error'] != None:
             raise JSONRPCException(resp['error'])
         else:
             return resp['result']         

This should work in Python is anybody ever needs it. I've updated the wiki,
https://en.bitcoin.it/wiki/API_tutorial_%28JSON-RPC%29#Python

It's based off the old lib.
legendary
Activity: 2576
Merit: 1186
This isn't the only (nor biggest) problem with JSON-RPC. Help create a new standard protocol fixing this and other problems: https://en.bitcoin.it/wiki/Wallet_protocol
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
GMP is an integer only library,

http://codepad.viper-7.com/pj58SK

You can still use bcmath, may be faster than working strings:

http://www.php.net/manual/en/book.bc.php

Also, somebody on the forums told me that there are many other libraries supporting arbitrary precision mathematics for PHP, but i don't know them myself because i never needed that.
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
OK, i have found the base for my allegations about dangers of using floats:

Warning
Floating point precision

Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error progragation must be considered when several operations are compounded.

Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....

So never trust floating number results to the last digit, and never compare floating point numbers for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

If this doesn't shout "floats are bad", then i don't know what else to say about that.

So everything i said was true. "Precision depends on the system". So it may be different on 32bit and 64bit systems, and perhaps even on windows / Linux / different types of Unix/BSD.
legendary
Activity: 1232
Merit: 1076
You can do everything in GMP except decode the JSON, which is what I think OP was complaining about.

No, I was complaining about the fact that the Bitcoin JSON-RPC Api uses numbers (that nearly all libraries convert to floats and have no option to change) when using strings would only be minorly impactful.
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
You can do everything in GMP except decode the JSON, which is what I think OP was complaining about.

This is a misunderstanding.
I only meant do the calculations in GMP, and only convert from/to string on input/output .

GMP is an integer only library,

http://codepad.viper-7.com/pj58SK

Ah sorry then, my mistake.
legendary
Activity: 1232
Merit: 1076
hero member
Activity: 588
Merit: 500
You can do everything in GMP except decode the JSON, which is what I think OP was complaining about.
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
legendary
Activity: 1232
Merit: 1076
Yeah those are integer values,

var_dump(gmp_strval(gmp_div_q(gmp_init("5"), gmp_init("2"))));

output:
string(1) "2" 

Here's my solution, http://codepad.viper-7.com/tbZ9oD
Code:

$quot 
gmp_init("5");
$divis gmp_init("2");
# number of decimals
$precision 2;

$shift gmp_pow("10"$precision);
$quot gmp_mul($quot$shift);

$res gmp_div_q($quot$divis);
$repr gmp_strval($res);
$dotpos strlen($repr) - $precision;
$repr substr($repr0$dotpos) . "." substr($repr$dotpos);

echo 
"Number is $repr";
$res gmp_init($repr);

Multiply the quotient by 10^p (p = precision), perform the integer division, convert to string, insert the decimal point, convert back to GMP.
legendary
Activity: 1470
Merit: 1006
Bringing Legendary Har® to you since 1952
ShadowOfHarbringer: Do you know how to divide numbers in PHP GMP and obtain a decimal number (not quotient + remainder)?

Well it should be fairly easy using GMP, however i have never done that before.

You will probably need to study usage of following functions:

http://www.php.net/manual/en/function.gmp-init.php
http://www.php.net/manual/en/function.gmp-div-q.php
http://www.php.net/manual/en/function.gmp-strval.php

Example from PHP.net:

Code:

$div1 
gmp_div_q("100""5");
echo 
gmp_strval($div1) . "\n";

$div2 gmp_div_q("1""3");
echo 
gmp_strval($div2) . "\n";

$div3 gmp_div_q("1""3"GMP_ROUND_PLUSINF);
echo 
gmp_strval($div3) . "\n";

$div4 gmp_div_q("-1""4"GMP_ROUND_PLUSINF);
echo 
gmp_strval($div4) . "\n";

$div5 gmp_div_q("-1""4"GMP_ROUND_MINUSINF);
echo 
gmp_strval($div5) . "\n";

And result:

Code:
20
0
1
0
-1
legendary
Activity: 1232
Merit: 1076
ShadowOfHarbringer: Do you know how to divide numbers in PHP GMP and obtain a decimal number (not quotient + remainder)?
Pages:
Jump to: