Author

Topic: slight error in difficulty computation (Read 1305 times)

newbie
Activity: 14
Merit: 0
May 28, 2011, 10:37:21 AM
#4

Because bc is better at arbitrary precision floating point calculation than bitcoin.

So I stumbled upon a bug in bitclient (a minor bug, obviously) Smiley
I would like to  point out that there's no need of an high precision calculator: target is a big number but with few significant digits. The maximum target has only 4  significant hex digits (FFFF), I don't know how many there are in the current target but I suppose there's no need for it to have many more.
legendary
Activity: 1072
Merit: 1174
There's already a patch to fix it, see https://github.com/bitcoin/bitcoin/pull/276
hero member
Activity: 504
Merit: 502
Because bc is better at arbitrary precision floating point calculation than bitcoin.

Bitcoin uses an approximation:

Code:
double GetDifficulty()
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (pindexBest == NULL)
        return 1.0;
    int nShift = 256 - 32 - 31; // to fit in a uint
    double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint();
    double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint();
    return dMinimum / dCurrently;
}

In case its not clear, it doesn't use the most significant bits, it just shifts the bignums representing the current target and the minimum target down by a fixed number of bits, and then divides those numbers to get a floating point answer.  It's not the best approximation for two reasons:

  • It potentially throws away resolution by assuming knowledge of the minimum target.  Fortunately that assumption is true.
  • Doubles contain more than 32 bits worth of precision, and the division is done with two 32 bit integers.

Short of implementing a full arbitrary precision floating point division (which isn't trivial), this psuedo code might be better:

Code:
unsigned int hb1, hb2;
hb1 = highest_bit( proofOfWorkLimit );
hb2 = highest_bit( currentTarget );
if( hb2 > hb1 )
  hb1 = hb2;
hb1 -= bits_of_precision_in_double;

uint64_t L = proofOfWorkLimit >> hb1;
uint64_t T = currentTarget >> hb1;

return (double)(L)/T;

To be honest though, there's no real reason to change it.  It's only used for displaying to users, never for calculations.  Other than for pride, there's no pressing need to fix it.
newbie
Activity: 14
Merit: 0
I don't understand this:

$ curl --url http://***:***@127.0.0.1:8332 -H 'content-type: text/plain;'  --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getwork", "params": [] }'
{"result":{"midstate":"df92c2b8aac64fc5d15a0ff08a8950453ce9e8fb1ecfa39cb8aeaca78bae173a","data":"0000000174dae8b4ae722300d81693b97993f4a57dc7c8151b980d4a00003bfc00000000b79f998 e1df8db02f7d2ba1676e7060a57fa8a5764990629f53173f8b61d8c1f4dde5b591a44b9f2000000 0000000080000000000000000000000000000000000000000000000000000000000000000000000 0000000000080020000","hash1":"0000000000000000000000000000000000000000000000000000000000000000000000800000000 0000000000000000000000000000000000000000000010000","target":"0000000000000000000000000000000000000000000000f2b944000000000000"},"error":null,"id":"curltest"}

$ curl --url http://***.***@127.0.0.1:8332 -H 'content-type: text/plain;'  --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getdifficulty", "params": [] }'
{"result":244139.48158254,"error":null,"id":"curltest"}

$ echo "base=10;ibase=16;scale=8;00000000FFFF0000000000000000000000000000000000000000000000000000 / 00000000000044B9F20000000000000000000000000000000000000000000000" |bc
244112.48777433


Why I get 244112.48777433 instead of 244139.48158254 ?

Enzo

Jump to: