Browse Source

Fix floating-point input from decimal string.

A bug was introduced in 3480230e: The divide-and-conquer method multiplies
with a power of the base, but this power is one too much if there is a
decimal point. This may happen because digits_to_I(...) is also called
from read_float(...). As a result, the number containd spurious zeros
(in the base used for reading it).

Thanks to Thomas Luthe <tluthe@physik.uni-bielefeld.de>.
master
Richard Kreckel 11 years ago
parent
commit
44e77b58d0
  1. 372
      src/integer/conv/cl_I_from_digits.cc

372
src/integer/conv/cl_I_from_digits.cc

@ -1,178 +1,194 @@
// digits_to_I(). // digits_to_I().
// General includes.
// General includes. #include "base/cl_sysdep.h"
#include "base/cl_sysdep.h" // Specification.
#include "integer/cl_I.h"
// Specification. // Implementation.
#include "integer/cl_I.h" #include "base/digitseq/cl_DS.h"
#include "integer/conv/cl_I_cached_power.h"
namespace cln {
// Implementation. static const cl_I digits_to_I_base2 (const char * MSBptr, uintC len, uintD base)
{
#include "base/digitseq/cl_DS.h" // base is a power of two: write the digits from least significant
#include "integer/conv/cl_I_cached_power.h" // to most significant into the result NUDS. Result needs
// 1+ceiling(len*log(base)/(intDsize*log(2))) or some more digits.
namespace cln { CL_ALLOCA_STACK;
var uintD* erg_MSDptr;
static const cl_I digits_to_I_base2 (const char * MSBptr, uintC len, uintD base) var uintC erg_len;
{ var uintD* erg_LSDptr;
// base is a power of two: write the digits from least significant var int b = (base==2 ? 1 : base==4 ? 2 : base==8 ? 3 : base==16 ? 4 : /*base==32*/ 5);
// to most significant into the result NUDS. Result needs num_stack_alloc(1+(len*b)/intDsize,,erg_LSDptr=);
// 1+ceiling(len*log(base)/(intDsize*log(2))) or some more digits erg_MSDptr = erg_LSDptr; erg_len = 0;
CL_ALLOCA_STACK; var uintD d = 0; // resulting digit
var uintD* erg_MSDptr; var int ch_where = 0; // position of ch inside d
var uintC erg_len; var uintC min_len = 0; // first non-zero digit
var uintD* erg_LSDptr; while (min_len < len && *(const uintB *)(MSBptr+min_len) == '0') {
var int b = (base==2 ? 1 : base==4 ? 2 : base==8 ? 3 : base==16 ? 4 : /*base==32*/ 5); ++min_len;
num_stack_alloc(1+(len*b)/intDsize,,erg_LSDptr=); }
erg_MSDptr = erg_LSDptr; erg_len = 0; while (len > min_len) {
var uintD d = 0; // resulting digit var uintB ch = *(const uintB *)(MSBptr+len-1); // next character
var int ch_where = 0; // position of ch inside d if (ch!='.') { // skip decimal point
var uintC min_len = 0; // first non-zero digit // Compute value of ch ('0'-'9','A'-'Z','a'-'z'):
while (min_len < len && *(const uintB *)(MSBptr+min_len) == '0') { ch = ch - '0';
++min_len; if (ch > '9'-'0') { // not a digit?
} ch = ch+'0'-'A'+10;
while (len > min_len) { if (ch > 'Z'-'A'+10) {// not an uppercase letter?
var uintB ch = *(const uintB *)(MSBptr+len-1); // next character ch = ch+'A'-'a'; // must be lowercase!
if (ch!='.') { // skip decimal point }
// Compute value of ch ('0'-'9','A'-'Z','a'-'z'): }
ch = ch - '0'; d = d | (uintD)ch<<ch_where;
if (ch > '9'-'0') { // not a digit? ch_where = ch_where+b;
ch = ch+'0'-'A'+10; if (ch_where >= intDsize) {
if (ch > 'Z'-'A'+10) {// not an uppercase letter? // d is ready to be written into the NUDS:
ch = ch+'A'-'a'; // must be lowercase! lsprefnext(erg_MSDptr) = d;
} ch_where = ch_where-intDsize;
} d = (uintD)ch >> b-ch_where; // carry
d = d | (uintD)ch<<ch_where; erg_len++;
ch_where = ch_where+b; }
if (ch_where >= intDsize) { }
// d is ready to be written into the NUDS: len--;
lsprefnext(erg_MSDptr) = d; }
ch_where = ch_where-intDsize; if (d != 0) { // is there anything left over?
d = (uintD)ch >> b-ch_where; // carry lsprefnext(erg_MSDptr) = d;
erg_len++; ++erg_len;
} }
} return NUDS_to_I(erg_MSDptr,erg_len);
len--; }
} static const cl_I digits_to_I_baseN (const char * MSBptr, uintC len, uintD base)
if (d != 0) { // is there anything left over? {
lsprefnext(erg_MSDptr) = d; // base is not a power of two: Add digits one by one. Result needs
++erg_len; // 1+ceiling(len*log(base)/(intDsize*log(2))) or some more digits.
} CL_ALLOCA_STACK;
return NUDS_to_I(erg_MSDptr,erg_len); var uintD* erg_MSDptr;
} var uintC erg_len;
var uintD* erg_LSDptr;
static const cl_I digits_to_I_baseN (const char * MSBptr, uintC len, uintD base) var uintC need = 1+floor(len,intDsize*256); // > len/(intDsize*256) >=0
{ switch (base) { // multiply need with ceiling(256*log(base)/log(2)):
// base is not a power of two: Add digits one by one. Result nees case 2: need = 256*need; break;
// 1+ceiling(len*log(base)/(intDsize*log(2))) or some more digits. case 3: need = 406*need; break;
CL_ALLOCA_STACK; case 4: need = 512*need; break;
var uintD* erg_MSDptr; case 5: need = 595*need; break;
var uintC erg_len; case 6: need = 662*need; break;
var uintD* erg_LSDptr; case 7: need = 719*need; break;
var uintC need = 1+floor(len,intDsize*256); // > len/(intDsize*256) >=0 case 8: need = 768*need; break;
switch (base) { // multiply need with ceiling(256*log(base)/log(2)): case 9: need = 812*need; break;
case 2: need = 256*need; break; case 10: need = 851*need; break;
case 3: need = 406*need; break; case 11: need = 886*need; break;
case 4: need = 512*need; break; case 12: need = 918*need; break;
case 5: need = 595*need; break; case 13: need = 948*need; break;
case 6: need = 662*need; break; case 14: need = 975*need; break;
case 7: need = 719*need; break; case 15: need = 1001*need; break;
case 8: need = 768*need; break; case 16: need = 1024*need; break;
case 9: need = 812*need; break; case 17: need = 1047*need; break;
case 10: need = 851*need; break; case 18: need = 1068*need; break;
case 11: need = 886*need; break; case 19: need = 1088*need; break;
case 12: need = 918*need; break; case 20: need = 1107*need; break;
case 13: need = 948*need; break; case 21: need = 1125*need; break;
case 14: need = 975*need; break; case 22: need = 1142*need; break;
case 15: need = 1001*need; break; case 23: need = 1159*need; break;
case 16: need = 1024*need; break; case 24: need = 1174*need; break;
case 17: need = 1047*need; break; case 25: need = 1189*need; break;
case 18: need = 1068*need; break; case 26: need = 1204*need; break;
case 19: need = 1088*need; break; case 27: need = 1218*need; break;
case 20: need = 1107*need; break; case 28: need = 1231*need; break;
case 21: need = 1125*need; break; case 29: need = 1244*need; break;
case 22: need = 1142*need; break; case 30: need = 1257*need; break;
case 23: need = 1159*need; break; case 31: need = 1269*need; break;
case 24: need = 1174*need; break; case 32: need = 1280*need; break;
case 25: need = 1189*need; break; case 33: need = 1292*need; break;
case 26: need = 1204*need; break; case 34: need = 1303*need; break;
case 27: need = 1218*need; break; case 35: need = 1314*need; break;
case 28: need = 1231*need; break; case 36: need = 1324*need; break;
case 29: need = 1244*need; break; default: NOTREACHED
case 30: need = 1257*need; break; }
case 31: need = 1269*need; break; // Now we have need >= len*log(base)/(intDsize*log(2)).
case 32: need = 1280*need; break; need += 1;
case 33: need = 1292*need; break; // Add digits one by one:
case 34: need = 1303*need; break; num_stack_alloc(need,,erg_LSDptr=);
case 35: need = 1314*need; break; // erg_MSDptr/erg_len/erg_LSDptr is a NUDS, erg_len < need.
case 36: need = 1324*need; break; erg_MSDptr = erg_LSDptr; erg_len = 0;
default: NOTREACHED while (len > 0) {
} var uintD newdigit = 0;
// Now we have need >= len*log(base)/(intDsize*log(2)). var uintC chx = 0;
need += 1; var uintD factor = 1;
// Add digits one by one: while (chx < power_table[base-2].k && len > 0) {
num_stack_alloc(need,,erg_LSDptr=); var uintB ch = *(const uintB *)MSBptr; MSBptr++; // next character
// erg_MSDptr/erg_len/erg_LSDptr is a NUDS, erg_len < need. // Compute value of ('0'-'9','A'-'Z','a'-'z'):
erg_MSDptr = erg_LSDptr; erg_len = 0; ch = ch-'0';
while (len > 0) { if (ch > '9'-'0') { // not a digit?
var uintD newdigit = 0; ch = ch+'0'-'A'+10;
var uintC chx = 0; if (ch > 'Z'-'A'+10) {// not an uppercase letter?
var uintD factor = 1; ch = ch+'A'-'a'; // must be lowercase!
while (chx < power_table[base-2].k && len > 0) { }
var uintB ch = *(const uintB *)MSBptr; MSBptr++; // next character }
if (ch!='.') { // skip decimal point factor = factor*base;
// Compute value of ('0'-'9','A'-'Z','a'-'z'): newdigit = base*newdigit+ch;
ch = ch-'0'; chx++;
if (ch > '9'-'0') { // not a digit? len--;
ch = ch+'0'-'A'+10; }
if (ch > 'Z'-'A'+10) {// not an uppercase letter? var uintD carry = mulusmall_loop_lsp(factor,erg_LSDptr,erg_len,newdigit);
ch = ch+'A'-'a'; // must be lowercase! if (carry!=0) {
} // need to extend NUDS:
} lsprefnext(erg_MSDptr) = carry;
factor = factor*base; erg_len++;
newdigit = base*newdigit+ch; }
chx++; }
} return NUDS_to_I(erg_MSDptr,erg_len);
len--; }
} static const cl_I digits_to_I_divconq (const char * MSBptr, uintC len, uintD base)
var uintD carry = mulusmall_loop_lsp(factor,erg_LSDptr,erg_len,newdigit); {
if (carry!=0) { // This is quite insensitive to the breakeven point.
// need to extend NUDS: // On a 1GHz Athlon I get approximately:
lsprefnext(erg_MSDptr) = carry; // base 3: breakeven around 25000
erg_len++; // base 10: breakeven around 8000
} // base 36: breakeven around 2000
} if (len>80000/base) {
return NUDS_to_I(erg_MSDptr,erg_len); // Divide-and-conquer:
} // Find largest i such that B = base^(k*2^i) satisfies B <= X.
var const cached_power_table_entry * p;
const cl_I digits_to_I (const char * MSBptr, uintC len, uintD base) var uintC len_B = power_table[base-2].k;
{ for (uintC i = 0; ; i++) {
if ((base & (base-1)) == 0) { p = cached_power(base, i);
return digits_to_I_base2(MSBptr, len, base); if (2*len_B >= len)
} else { break;
// This is quite insensitive to the breakeven point. len_B = len_B*2;
// On a 1GHz Athlon I get approximately: }
// base 3: breakeven around 25000 return digits_to_I_divconq(MSBptr,len-len_B,base) * p->base_pow
// base 10: breakeven around 8000 + digits_to_I_divconq(MSBptr+len-len_B,len_B,base);
// base 36: breakeven around 2000 } else {
if (len>80000/base) { return digits_to_I_baseN(MSBptr, len, base);
// Divide-and-conquer: }
// Find largest i such that B = base^(k*2^i) satisfies B <= X. }
var const cached_power_table_entry * p; const cl_I digits_to_I (const char * MSBptr, uintC len, uintD base)
var uintC len_B = power_table[base-2].k; {
for (uintC i = 0; ; i++) { if ((base & (base-1)) == 0) {
p = cached_power(base, i); return digits_to_I_base2(MSBptr, len, base);
if (2*len_B >= len) } else {
break; // digits_to_I_divconq cannot handle decimal points, so remove it here
len_B = len_B*2; CL_ALLOCA_STACK;
} const uintD * digits_copy;
return digits_to_I(MSBptr,len-len_B,base)*p->base_pow num_stack_alloc(len,,digits_copy=);
+digits_to_I(MSBptr+len-len_B,len_B,base); char * copy_ptr = (char *)digits_copy;
} else { uintC n = 0;
return digits_to_I_baseN(MSBptr, len, base); for (uintC i = 0; i < len; ++i) {
} const char ch = MSBptr[i];
} if (ch != '.') { // skip decimal point
} copy_ptr[n] = ch;
n++;
} // namespace cln }
}
return digits_to_I_divconq((const char*)digits_copy, n, base);
}
}
} // namespace cln
|||||||
100:0
Loading…
Cancel
Save