diff options
author | Mike Buland <mike@xagasoft.com> | 2014-10-30 13:15:19 -0600 |
---|---|---|
committer | Mike Buland <mike@xagasoft.com> | 2014-10-30 13:15:19 -0600 |
commit | 7026b96ec807b169f7b413056e52412ae422ea9d (patch) | |
tree | 9a597b31b8c7d6a8781b45d1bbf27c258bb6a3a4 /src/number.cpp | |
parent | 18a2be05bfacddcb7398f1b197bd1a5876c9a0cb (diff) | |
download | clic-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.
Diffstat (limited to '')
-rw-r--r-- | src/number.cpp | 248 |
1 files changed, 118 insertions, 130 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 | ||
383 | void Number::divide( const Number &rhs, Number &q, Number &r ) const | 396 | void 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 | ||
521 | bool Number::isZero() const | 498 | bool 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 | ||
588 | int 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 | |||
611 | int32_t Number::toInt32() const | 597 | int32_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; |