summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2014-10-30 13:15:19 -0600
committerMike Buland <mike@xagasoft.com>2014-10-30 13:15:19 -0600
commit7026b96ec807b169f7b413056e52412ae422ea9d (patch)
tree9a597b31b8c7d6a8781b45d1bbf27c258bb6a3a4
parent18a2be05bfacddcb7398f1b197bd1a5876c9a0cb (diff)
downloadclic-7026b96ec807b169f7b413056e52412ae422ea9d.tar.gz
clic-7026b96ec807b169f7b413056e52412ae422ea9d.tar.bz2
clic-7026b96ec807b169f7b413056e52412ae422ea9d.tar.xz
clic-7026b96ec807b169f7b413056e52412ae422ea9d.zip
The new division works great!
Other minor bug fixes including scale issues, digit() access stopped a digit before the final possible digit in the scale, >, >=, <, <= all work correctly with mixed scale numbers now, probably other fixes.
-rw-r--r--src/number.cpp248
-rw-r--r--src/number.h1
-rw-r--r--src/options.cpp1
-rw-r--r--src/parser.cpp4
-rw-r--r--src/unitnumber.cpp8
-rw-r--r--src/unitnumber.h1
-rw-r--r--src/unitparser.cpp4
7 files changed, 134 insertions, 133 deletions
diff --git a/src/number.cpp b/src/number.cpp
index 0b8e07b..c23466e 100644
--- a/src/number.cpp
+++ b/src/number.cpp
@@ -186,9 +186,15 @@ bool Number::operator>( const Number &rhs ) const
186 else if( iDiff > 0 ) 186 else if( iDiff > 0 )
187 return bPositive; 187 return bPositive;
188 } 188 }
189 for( int j = 0; j < iScale; j++ ) 189 int iMax = iScale;
190 if( rhs.iScale > iMax )
191 iMax = rhs.iScale;
192// Bu::println("Max scale = %1").arg( iMax );
193 for( int j = 0; j < iMax; j++ )
190 { 194 {
191 int iDiff = aFrac[j] - rhs.aFrac[j]; 195// Bu::println(" > at %1 (%2 > %3)").arg( j )
196// .arg( digit(-1-j) ).arg( rhs.digit(-1-j) );
197 int iDiff = digit(-1-j) - rhs.digit(-1-j);
192 if( iDiff < 0 ) 198 if( iDiff < 0 )
193 return !bPositive; 199 return !bPositive;
194 else if( iDiff > 0 ) 200 else if( iDiff > 0 )
@@ -219,9 +225,12 @@ bool Number::operator<( const Number &rhs ) const
219 else if( iDiff < 0 ) 225 else if( iDiff < 0 )
220 return bPositive; 226 return bPositive;
221 } 227 }
222 for( int j = 0; j < iScale; j++ ) 228 int iMax = iScale;
229 if( rhs.iScale > iMax )
230 iMax = rhs.iScale;
231 for( int j = 0; j < iMax; j++ )
223 { 232 {
224 int iDiff = aFrac[j] - rhs.aFrac[j]; 233 int iDiff = digit(-1-j) - rhs.digit(-1-j);
225 if( iDiff > 0 ) 234 if( iDiff > 0 )
226 return !bPositive; 235 return !bPositive;
227 else if( iDiff < 0 ) 236 else if( iDiff < 0 )
@@ -244,17 +253,18 @@ bool Number::operator>=( const Number &rhs ) const
244 253
245 for( int j = aInt.getSize()-1; j >= 0; j-- ) 254 for( int j = aInt.getSize()-1; j >= 0; j-- )
246 { 255 {
247// Bu::println(" --> %1 > %2 -> %3").arg( aInt[j] ).arg( rhs.aInt[j] ).
248// arg( aInt[j] > rhs.aInt[j] );
249 int iDiff = aInt[j] - rhs.aInt[j]; 256 int iDiff = aInt[j] - rhs.aInt[j];
250 if( iDiff < 0 ) 257 if( iDiff < 0 )
251 return !bPositive; 258 return !bPositive;
252 else if( iDiff > 0 ) 259 else if( iDiff > 0 )
253 return bPositive; 260 return bPositive;
254 } 261 }
255 for( int j = 0; j < iScale; j++ ) 262 int iMax = iScale;
263 if( rhs.iScale > iMax )
264 iMax = rhs.iScale;
265 for( int j = 0; j < iMax; j++ )
256 { 266 {
257 int iDiff = aFrac[j] - rhs.aFrac[j]; 267 int iDiff = digit(-1-j) - rhs.digit(-1-j);
258 if( iDiff < 0 ) 268 if( iDiff < 0 )
259 return !bPositive; 269 return !bPositive;
260 else if( iDiff > 0 ) 270 else if( iDiff > 0 )
@@ -285,9 +295,12 @@ bool Number::operator<=( const Number &rhs ) const
285 else if( iDiff < 0 ) 295 else if( iDiff < 0 )
286 return bPositive; 296 return bPositive;
287 } 297 }
288 for( int j = 0; j < iScale; j++ ) 298 int iMax = iScale;
299 if( rhs.iScale > iMax )
300 iMax = rhs.iScale;
301 for( int j = 0; j < iMax; j++ )
289 { 302 {
290 int iDiff = aFrac[j] - rhs.aFrac[j]; 303 int iDiff = digit(-1-j) - rhs.digit(-1-j);
291 if( iDiff > 0 ) 304 if( iDiff > 0 )
292 return !bPositive; 305 return !bPositive;
293 else if( iDiff < 0 ) 306 else if( iDiff < 0 )
@@ -382,140 +395,104 @@ void Number::set( int32_t iNum )
382 395
383void Number::divide( const Number &rhs, Number &q, Number &r ) const 396void Number::divide( const Number &rhs, Number &q, Number &r ) const
384{ 397{
385 if( rhs.iScale > 0 ) 398// Bu::println("divide: %1 / %2").arg( *this ).arg( rhs );
386 {
387 Number newrhs = Number( 0, iRadix );
388 Number newbase = Number( iScale, iRadix );
389 int iOff;
390 for( iOff = -iScale; iOff < 0 && rhs.digit( iOff ) == 0; iOff++ ) { }
391 if( iOff < 0 )
392 {
393 for( int j = iOff; j < rhs.aInt.getSize(); j++ )
394 {
395 newrhs.aInt.append( rhs.digit( j ) );
396 newbase.aInt.append( digit( j ) );
397 }
398 for( int j = rhs.aInt.getSize(); j < aInt.getSize(); j++ )
399 {
400 newbase.aInt.append( aInt.get( j ) );
401 }
402 for( int j = iScale+iOff; j >= -iOff; j-- )
403 {
404 newbase.aFrac.set( j+iOff, aFrac.get( j ) );
405 }
406 399
407// Bu::println("Conv %1 => %2 (iOff = %3)").arg( rhs ).arg( newrhs ).arg( iOff ); 400 // iNumShift is how many digits we've shifted the entire equation,
408// Bu::println("Conv %1 => %2 (iOff = %3)").arg( *this ).arg( newbase ).arg( iOff ); 401 // effectively multiplying the numerator and divisor by iRadix*iNumShift
402 int iNumShift = rhs.getEffectiveScale();
403// Bu::println("iNumShift = %1").arg( iNumShift );
409 404
410 newbase.divide( newrhs, q, r ); 405 // Setup our divisor, this is important, it should be an integer to make
411 return; 406 // things easy, and it won't change once we create it.
412 } 407 Number nDiv( 0, iRadix );
408 for( int j = -iNumShift; j < rhs.aInt.getSize(); j++ )
409 {
410// Bu::println(" -> '%1'").arg( rhs.digit( j ) );
411 nDiv.aInt.append( rhs.digit( j ) );
413 } 412 }
414 413// Bu::println("New divisor: %1").arg( nDiv );
415 q = Number( iScale, iRadix );
416 r = *this;
417
418 if( bPositive == rhs.bPositive )
419 q.bPositive = true;
420 else
421 q.bPositive = false;
422
423 int iMinWidth = Bu::buMax(1,rhs.aInt.getSize());
424 414
425 int iAnchor = r.aInt.getSize()-iMinWidth; 415 // Anchor is the position in the output the new digit will appear.
426 int iSample = iMinWidth; 416 // This also tells us where the ones place will be in our new numerator.
427 do 417 int iAnchor = (aInt.getSize()+iNumShift)-nDiv.aInt.getSize();
418// Bu::println("Anchor: %1").arg( iAnchor );
419
420 // Setup our output variables
421 q.iRadix = r.iRadix = iRadix;
422 q.iScale = r.iScale = iScale;
423 q.bPositive = !(!bPositive ^ !rhs.bPositive);
424 r.bPositive = true;
425 q.aInt.clear();
426 r.aInt.clear();
427 if( q.aFrac.getSize() != iScale )
428 q.aFrac = PackedIntArray( aFrac.getBitWidth(), iScale );
429 if( r.aFrac.getSize() != iScale )
430 r.aFrac = PackedIntArray( aFrac.getBitWidth(), iScale );
431
432 // The numerator is re-created every step to match the divisor and
433 // anchor
434 Number nNum( iScale, iRadix );
435 for( int j = iAnchor-iNumShift;
436 nNum.aInt.getSize() < nDiv.aInt.getSize(); j++ )
437 {
438// Bu::println(" ->[%1] '%2'").arg( j ).arg( digit(j) );
439 nNum.aInt.append( digit( j ) );
440 }
441// Bu::println("New numerator: %1").arg( nNum );
442 while( iAnchor > -iScale && !nNum.isZero()) // division loop
428 { 443 {
429// Bu::println("%1\n-----").arg( r.aInt.toString() ); 444 // As long as the numerator is smaller than the divisor we keep
430 Number sub( 0, iRadix ); 445 // including new digits.
431 if( iAnchor < 0 ) 446 while( nNum < nDiv )
432 { 447 {
433 sub = r; 448 iAnchor--;
434 sub.aInt.insert(0,0); 449 nNum.aInt.insert( 0, digit(iAnchor-iNumShift) );
450// Bu::println("Numerator too small, new numerator: %1").arg( nNum );
435 } 451 }
436 for(;;) 452 if( iAnchor < -iScale )
453 break;
454
455// Bu::println(" New anchor: %1").arg( iAnchor );
456
457 // How many times does the divisor fit into the numerator
458 int iCount = 0;
459 for(;nNum >= nDiv; iCount++ )
437 { 460 {
438// Bu::println(" -> Anchor: %1, Sample: %2").arg( iAnchor ).arg( iSample ); 461// Bu::print(" ==> step %3: %1 - %2 = ").arg( nNum ).arg( nDiv ).arg( iCount );
439 if( iAnchor >= 0 ) 462 nNum = nNum - nDiv;
440 { 463// Bu::println("%1").arg( nNum );
441 sub.aInt.set( r.aInt, iAnchor, iSample );
442 }
443 else
444 {
445/* sub.aInt.clear();
446 for( int j = iAnchor; j < r.aInt.getSize(); j++ )
447 {
448 sub.aInt.append( r.digit( j ) );
449 }
450 */
451 }
452// Bu::println("%1\n%2\n----").arg( sub.toString() ).arg( rhs.toString() );
453 if( sub < rhs )
454 {
455 iSample++;
456 iAnchor--;
457 if( iAnchor < 0 )
458 {
459 if( r.isZero() || iAnchor < -iScale )
460 {
461// Bu::println("[Inner exit] Complete: q = %1, r = %2").arg( q.toString() ).arg( r.toString() );
462 return;
463 }
464 sub.aInt.insert(0, 0);
465 }
466 }
467 else
468 break;
469 } 464 }
465// Bu::println("Total steps: %1").arg( iCount );
470 466
471 Number x( 0, iRadix ); 467 if( iAnchor >= 0 )
472 int iRes = -1;
473// Bu::println("{x = %1, sub=%2, rhs=%4, iRes=%3}").arg( x ).arg(sub).arg(iRes).arg(rhs);
474 for( ; x <= sub; iRes++, x = x + rhs ) {
475// Bu::println("{x = %1, sub=%2, rhs=%4, iRes=%3, x+rhs=%5}").arg( x ).arg(sub).arg(iRes).arg(rhs).arg(x+rhs);
476 }
477 x = sub - (x - rhs);
478 if( !x.bPositive )
479 { 468 {
480 iSample++; 469 while( q.aInt.getSize() <= iAnchor )
481 iAnchor--; 470 q.aInt.append( 0 );
482// Bu::println("What? it's negative? %1").arg( x ); 471 q.aInt.set( iAnchor, iCount );
483 continue;
484 } 472 }
485 if( iAnchor < 0 ) 473 else
486 { 474 {
487 r = x; 475 while( q.aFrac.getSize() <= -1-iAnchor )
476 q.aFrac.append( 0 );
477 q.aFrac.set( -1-iAnchor, iCount );
488 } 478 }
489 else 479 }
480 for( int j = -iAnchor; j < nNum.aInt.getSize(); j++ )
481 r.aInt.append( nNum.aInt[j] );
482 int jtop = 0;
483 for(; nNum.aInt[jtop] == 0; jtop++ ) { }
484// Bu::println("Computing remainder fraction from %1 to %2")
485// .arg( -iAnchor-1 ).arg( jtop );
486 for( int j = -iAnchor-1, k = 0; j >= jtop && k < r.iScale; j--, k++ )
487 {
488 if( j <= nNum.aInt.getSize() )
490 { 489 {
491 for( int j = 0; j < x.aInt.getSize(); j++ ) 490 r.aFrac.set( k, nNum.aInt[j] );
492 r.aInt.set( iAnchor+j, x.aInt.get( j ) ); 491// Bu::println("setting %1 to %2").arg( k ).arg( nNum.aInt[j] );
493 } 492 }
494 493 }
495 while( r.aInt.getSize() > Bu::buMax(0,iAnchor)+x.aInt.getSize() ) 494// Bu::println("Final numerator? %1").arg( nNum );
496 r.aInt.remove(); 495// Bu::println("Remainder? %1").arg( r );
497// Bu::println(" -> Post remainder patch: %1 -> %2").
498// arg( x.toString() ).arg( r.toString() );
499
500// Bu::println("%1 (%2)").arg( iRes ).arg( x.toString() );
501 while( q.aInt.getSize() <= iAnchor )
502 q.aInt.append(0);
503 if( iAnchor >= 0 )
504 q.aInt.set( iAnchor, iRes );
505 else
506 q.aFrac.set( -1-iAnchor, iRes );
507
508 iSample = iMinWidth;
509 if( iAnchor > 0 )
510 iAnchor -= rhs.aInt.getSize()-x.aInt.getSize();
511 else
512 iAnchor--;
513// iAnchor = r.aInt.getSize()-iMinWidth;
514// Bu::println(" -> new Anchor: %1, Sample: %2").arg( iAnchor ).
515// arg( iSample );
516 } while( iAnchor >= -iScale );
517
518// Bu::println("Complete: q = %1, r = %2").arg( q.toString() ).arg( r.toString() );
519} 496}
520 497
521bool Number::isZero() const 498bool Number::isZero() const
@@ -579,7 +556,7 @@ int Number::digit( int iIdx ) const
579{ 556{
580 if( iIdx < 0 ) 557 if( iIdx < 0 )
581 { 558 {
582 if( iIdx <= -iScale ) 559 if( iIdx < -iScale )
583 return 0; 560 return 0;
584 else 561 else
585 return aFrac[-1-iIdx]; 562 return aFrac[-1-iIdx];
@@ -608,6 +585,15 @@ void Number::setScale( int iNewScale )
608 iScale = iNewScale; 585 iScale = iNewScale;
609} 586}
610 587
588int Number::getEffectiveScale() const
589{
590 if( iScale == 0 )
591 return 0;
592 int iSigDig = iScale-1;
593 for( ; iSigDig >= 0 && aFrac.get( iSigDig ) == 0; iSigDig-- ) { }
594 return iSigDig+1;
595}
596
611int32_t Number::toInt32() const 597int32_t Number::toInt32() const
612{ 598{
613 int32_t ret = 0; 599 int32_t ret = 0;
@@ -632,8 +618,10 @@ Number Number::toRadix( int iNewRadix, int iNewScale ) const
632 n.set( iNewRadix ); 618 n.set( iNewRadix );
633 while( !me.isZero() ) 619 while( !me.isZero() )
634 { 620 {
635 ret.aInt.append( (me%n).toInt32() ); 621 int dig = (me%n).toInt32();
622 ret.aInt.append( dig );
636 me = me / n; 623 me = me / n;
624 Bu::println("New digit: %1 (%2)").arg( dig ).arg( me );
637 } 625 }
638 626
639 return ret; 627 return ret;
diff --git a/src/number.h b/src/number.h
index 40dbd55..fe10788 100644
--- a/src/number.h
+++ b/src/number.h
@@ -47,6 +47,7 @@ public:
47 int digit( int iIdx ) const; 47 int digit( int iIdx ) const;
48 48
49 int getScale() const { return iScale; } 49 int getScale() const { return iScale; }
50 int getEffectiveScale() const;
50 void setScale( int iNewScale ); 51 void setScale( int iNewScale );
51 52
52 int32_t toInt32() const; 53 int32_t toInt32() const;
diff --git a/src/options.cpp b/src/options.cpp
index 6e264f9..3581500 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -150,6 +150,7 @@ int Options::convert( Bu::StringArray aArgs )
150 iToRadix = strtol( lBits.last().getStr(), 0, 10 ); 150 iToRadix = strtol( lBits.last().getStr(), 0, 10 );
151 n = Number( *(lBits.begin()+1), 0, iFromRadix ); 151 n = Number( *(lBits.begin()+1), 0, iFromRadix );
152 } 152 }
153 Bu::println("%1").arg( n.toString() );
153 Bu::println("%1").arg( n.toRadix( iToRadix ).toString() ); 154 Bu::println("%1").arg( n.toRadix( iToRadix ).toString() );
154 } 155 }
155 156
diff --git a/src/parser.cpp b/src/parser.cpp
index 607de8a..8675a7c 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -232,9 +232,11 @@ void Parser::unwind()
232 { 232 {
233 Token b = tsTerminal.peekPop(); 233 Token b = tsTerminal.peekPop();
234 Token a = tsTerminal.peekPop(); 234 Token a = tsTerminal.peekPop();
235 Number *pProduct = new Number( deref(a) * deref(b) );
236 pProduct->setScale( lex.getScale() );
235 tsTerminal.push( 237 tsTerminal.push(
236 Token( Token::tNumber, 238 Token( Token::tNumber,
237 new Number( deref(a) * deref(b) ) 239 pProduct
238 ) 240 )
239 ); 241 );
240 } 242 }
diff --git a/src/unitnumber.cpp b/src/unitnumber.cpp
index 1d63682..4846a07 100644
--- a/src/unitnumber.cpp
+++ b/src/unitnumber.cpp
@@ -15,6 +15,8 @@ UnitNumber::UnitNumber()
15 "parse1", Bu::UnitSuite::expectPass ); 15 "parse1", Bu::UnitSuite::expectPass );
16 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::multiply1), 16 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::multiply1),
17 "multiply1", Bu::UnitSuite::expectPass ); 17 "multiply1", Bu::UnitSuite::expectPass );
18 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::divide1),
19 "divide1", Bu::UnitSuite::expectPass );
18 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::number1), 20 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::number1),
19 "number1", Bu::UnitSuite::expectPass ); 21 "number1", Bu::UnitSuite::expectPass );
20 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::compare1), 22 add( static_cast<Bu::UnitSuite::Test>(&UnitNumber::compare1),
@@ -68,6 +70,12 @@ void UnitNumber::multiply1()
68 ); 70 );
69} 71}
70 72
73void UnitNumber::divide1()
74{
75 unitTest(Number("4") / Number("10") == "0");
76 unitTest(Number("4") % Number("10") == "4");
77}
78
71#define mathTest( anum, op, bnum, answ ) \ 79#define mathTest( anum, op, bnum, answ ) \
72 unitTest( (Number(anum) op Number(bnum)).toString() == answ ) 80 unitTest( (Number(anum) op Number(bnum)).toString() == answ )
73 81
diff --git a/src/unitnumber.h b/src/unitnumber.h
index 83da27f..96d882e 100644
--- a/src/unitnumber.h
+++ b/src/unitnumber.h
@@ -12,6 +12,7 @@ public:
12 void packed1(); 12 void packed1();
13 void parse1(); 13 void parse1();
14 void multiply1(); 14 void multiply1();
15 void divide1();
15 void number1(); 16 void number1();
16 void compare1(); 17 void compare1();
17 void radix1(); 18 void radix1();
diff --git a/src/unitparser.cpp b/src/unitparser.cpp
index 891f7b3..43dacfc 100644
--- a/src/unitparser.cpp
+++ b/src/unitparser.cpp
@@ -33,7 +33,7 @@ void UnitParser::order1()
33 unitTest(parse("2+3*5") == "17"); 33 unitTest(parse("2+3*5") == "17");
34 unitTest(parse("2+3-5") == "0"); 34 unitTest(parse("2+3-5") == "0");
35 unitTest(parse("(2+3)*5") == "25"); 35 unitTest(parse("(2+3)*5") == "25");
36 unitTest(parse("1.59*40/24*21", 5) == "55.125"); 36 unitTest(parse("1.59*40/24*21", 5) == "55.65");
37 unitTest(parse("1.59*40/(24*21)", 5) == "0.125"); // bc says it's this: "0.12619"); 37 unitTest(parse("1.59*40/(24*21)", 5) == "0.12619"); // bc says it's this: "0.12619");
38} 38}
39 39