Bitcoin Forum
May 08, 2024, 10:55:32 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 [2] 3 4 5 »  All
  Print  
Author Topic: why JSON RPC values not use INT64 instead of float string?  (Read 18410 times)
error
Hero Member
*****
Offline Offline

Activity: 588
Merit: 500



View Profile
March 11, 2011, 10:55:52 PM
 #21

You can do everything in GMP except decode the JSON, which is what I think OP was complaining about.

3KzNGwzRZ6SimWuFAgh4TnXzHpruHMZmV8
"There should not be any signed int. If you've found a signed int somewhere, please tell me (within the next 25 years please) and I'll change it to unsigned int." -- Satoshi
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1715208932
Hero Member
*
Offline Offline

Posts: 1715208932

View Profile Personal Message (Offline)

Ignore
1715208932
Reply with quote  #2

1715208932
Report to moderator
genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 11, 2011, 10:57:50 PM
 #22

GMP is an integer only library,

http://codepad.viper-7.com/pj58SK
ShadowOfHarbringer
Legendary
*
Offline Offline

Activity: 1470
Merit: 1005


Bringing Legendary Har® to you since 1952


View Profile
March 11, 2011, 10:59:19 PM
 #23

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.

genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 11, 2011, 11:00:04 PM
 #24

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.
ShadowOfHarbringer
Legendary
*
Offline Offline

Activity: 1470
Merit: 1005


Bringing Legendary Har® to you since 1952


View Profile
March 11, 2011, 11:07:10 PM
 #25

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.

ShadowOfHarbringer
Legendary
*
Offline Offline

Activity: 1470
Merit: 1005


Bringing Legendary Har® to you since 1952


View Profile
March 11, 2011, 11:15:04 PM
 #26

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.

Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2576
Merit: 1186



View Profile
March 12, 2011, 02:05:17 AM
 #27

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

genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 12, 2011, 04:09:03 AM
 #28

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.
genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 12, 2011, 05:52:18 AM
Last edit: March 12, 2011, 02:10:54 PM by genjix
 #29

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
mizerydearia
Hero Member
*****
Offline Offline

Activity: 574
Merit: 507



View Profile
March 12, 2011, 05:59:10 AM
 #30

Also see http://meta.witcoin.com/p/348/Transactions---float-conversion-issue
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652
Merit: 2216


Chief Scientist


View Profile WWW
March 12, 2011, 03:24:51 PM
Last edit: March 14, 2011, 11:49:04 AM by gavinandresen
 #31

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?

How often do you get the chance to work on a potentially world-changing project?
genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 12, 2011, 03:57:26 PM
 #32

Code:
<?php
$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.
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652
Merit: 2216


Chief Scientist


View Profile WWW
March 12, 2011, 04:12:07 PM
 #33

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.


How often do you get the chance to work on a potentially world-changing project?
genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 12, 2011, 04:37:03 PM
 #34

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.
ShadowOfHarbringer
Legendary
*
Offline Offline

Activity: 1470
Merit: 1005


Bringing Legendary Har® to you since 1952


View Profile
March 12, 2011, 05:29:31 PM
 #35

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.

genjix (OP)
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1076


View Profile
March 12, 2011, 05:31:43 PM
 #36

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.
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652
Merit: 2216


Chief Scientist


View Profile WWW
March 12, 2011, 05:35:32 PM
 #37

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.

You know, I was looking at the PayPal payment API yesterday, and $1.01 is sent as... 1.01

"transmitting" != "calculations"

How often do you get the chance to work on a potentially world-changing project?
ShadowOfHarbringer
Legendary
*
Offline Offline

Activity: 1470
Merit: 1005


Bringing Legendary Har® to you since 1952


View Profile
March 12, 2011, 06:24:26 PM
 #38

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.

You know, I was looking at the PayPal payment API yesterday, and $1.01 is sent as... 1.01

"transmitting" != "calculations"

Of course you're right.
I was merely stating the fact.

j16sdiz
Newbie
*
Offline Offline

Activity: 37
Merit: 0


View Profile
March 14, 2011, 07:50:25 AM
 #39

....
Quote
> php -r "printf('%.8f', 0.94);"    #CORRECT
0.94000000
> php -r "printf('%.16f', 0.94);"   #WRONG
0.9399999999999999
....


It does not work that way ..  printf("%.8f") behaviour is inconsistent across platform. If you don't believe, try

Code:
printf("%.2f", -999.04)

-- some platform give  -999.03, some give -999.04.

Of course, you can fix this.... in your code. (But never expect all 3rd party apps do it right)
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652
Merit: 2216


Chief Scientist


View Profile WWW
March 14, 2011, 11:55:07 AM
 #40

It does not work that way ..  printf("%.8f") behaviour is inconsistent across platform. If you don't believe, try

Code:
printf("%.2f", -999.04)

-- some platform give  -999.03, some give -999.04.

I tried it... got -999.04 on my Mac and Linux machines.  What platform gives the wrong answer?

How often do you get the chance to work on a potentially world-changing project?
Pages: « 1 [2] 3 4 5 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!