Skip to content

Commit 7b63e0f

Browse files
committed
- lift def of getReside() up from toRepeatingDecimal()
- document them both better - test for both for limit < size(repeating-decimal)
1 parent 1ec7a95 commit 7b63e0f

File tree

2 files changed

+80
-57
lines changed

2 files changed

+80
-57
lines changed

src/js/base/js-numbers.js

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3871,6 +3871,69 @@ define("pyret-base/js/js-numbers", function() {
38713871
return asin(this.toFixnum(), errbacks);
38723872
};
38733873

3874+
//////////////////////////////////////////////////////////////////////
3875+
// getResidue: integer, integer, integer -> [string, string]
3876+
//
3877+
// Given the numerator and denominator of a proper (<= 1) fraction,
3878+
// returns two strings constituting its repeating-decimal representation,
3879+
// where the first string is the non-repeating digits immediately after the
3880+
// decimal point, and the second string is the repeating digits thereafter.
3881+
// The third argument is the limit on the size of the repeating digits.
3882+
// If exceeded, the second string is `...`.
3883+
var getResidue = function(r, d, limit, errbacks) {
3884+
var digits = [];
3885+
var seenRemainders = {};
3886+
seenRemainders[r] = true;
3887+
while(true) {
3888+
if (limit-- <= 0) {
3889+
return [digits.join(''), '...']
3890+
}
3891+
3892+
var nextDigit = quotient(
3893+
multiply(r, 10, errbacks), d, errbacks);
3894+
var nextRemainder = remainder(
3895+
multiply(r, 10, errbacks),
3896+
d, errbacks);
3897+
digits.push(nextDigit.toString());
3898+
if (seenRemainders[nextRemainder]) {
3899+
r = nextRemainder;
3900+
break;
3901+
} else {
3902+
seenRemainders[nextRemainder] = true;
3903+
r = nextRemainder;
3904+
}
3905+
}
3906+
3907+
var firstRepeatingRemainder = r;
3908+
var repeatingDigits = [];
3909+
while (true) {
3910+
var nextDigit = quotient(multiply(r, 10, errbacks), d, errbacks);
3911+
var nextRemainder = remainder(
3912+
multiply(r, 10, errbacks),
3913+
d, errbacks);
3914+
repeatingDigits.push(nextDigit.toString());
3915+
if (equals(nextRemainder, firstRepeatingRemainder, errbacks)) {
3916+
break;
3917+
} else {
3918+
r = nextRemainder;
3919+
}
3920+
};
3921+
3922+
var digitString = digits.join('');
3923+
var repeatingDigitString = repeatingDigits.join('');
3924+
3925+
while (digitString.length >= repeatingDigitString.length &&
3926+
(digitString.substring(
3927+
digitString.length - repeatingDigitString.length)
3928+
=== repeatingDigitString)) {
3929+
digitString = digitString.substring(
3930+
0, digitString.length - repeatingDigitString.length);
3931+
}
3932+
3933+
return [digitString, repeatingDigitString];
3934+
3935+
};
3936+
38743937
//////////////////////////////////////////////////////////////////////
38753938
// toRepeatingDecimal: jsnum jsnum {limit: number}? -> [string, string, string]
38763939
//
@@ -3880,64 +3943,13 @@ define("pyret-base/js/js-numbers", function() {
38803943
// non-repeating digits after the decimal, and the third are the
38813944
// remaining repeating decimals.
38823945
//
3883-
// An optional limit on the decimal expansion can be provided, in which
3884-
// case the search cuts off if we go past the limit.
3885-
// If this happens, the third argument returned becomes '...' to indicate
3946+
// An optional limit on the decimal expansion can be provided via
3947+
// a `limit` field of an object supplied as a third argument. This
3948+
// cuts off the search if we go past the limit.
3949+
// If this happens, the third string returned becomes '...' to indicate
38863950
// that the search was prematurely cut off.
3951+
// The default limit is 512.
38873952
var toRepeatingDecimal = (function() {
3888-
var getResidue = function(r, d, limit, errbacks) {
3889-
var digits = [];
3890-
var seenRemainders = {};
3891-
seenRemainders[r] = true;
3892-
while(true) {
3893-
if (limit-- <= 0) {
3894-
return [digits.join(''), '...']
3895-
}
3896-
3897-
var nextDigit = quotient(
3898-
multiply(r, 10, errbacks), d, errbacks);
3899-
var nextRemainder = remainder(
3900-
multiply(r, 10, errbacks),
3901-
d, errbacks);
3902-
digits.push(nextDigit.toString());
3903-
if (seenRemainders[nextRemainder]) {
3904-
r = nextRemainder;
3905-
break;
3906-
} else {
3907-
seenRemainders[nextRemainder] = true;
3908-
r = nextRemainder;
3909-
}
3910-
}
3911-
3912-
var firstRepeatingRemainder = r;
3913-
var repeatingDigits = [];
3914-
while (true) {
3915-
var nextDigit = quotient(multiply(r, 10, errbacks), d, errbacks);
3916-
var nextRemainder = remainder(
3917-
multiply(r, 10, errbacks),
3918-
d, errbacks);
3919-
repeatingDigits.push(nextDigit.toString());
3920-
if (equals(nextRemainder, firstRepeatingRemainder, errbacks)) {
3921-
break;
3922-
} else {
3923-
r = nextRemainder;
3924-
}
3925-
};
3926-
3927-
var digitString = digits.join('');
3928-
var repeatingDigitString = repeatingDigits.join('');
3929-
3930-
while (digitString.length >= repeatingDigitString.length &&
3931-
(digitString.substring(
3932-
digitString.length - repeatingDigitString.length)
3933-
=== repeatingDigitString)) {
3934-
digitString = digitString.substring(
3935-
0, digitString.length - repeatingDigitString.length);
3936-
}
3937-
3938-
return [digitString, repeatingDigitString];
3939-
3940-
};
39413953

39423954
return function(n, d, options, errbacks) {
39433955
// default limit on decimal expansion; can be overridden
@@ -4099,6 +4111,7 @@ define("pyret-base/js/js-numbers", function() {
40994111
_integerGreaterThanOrEqual: _integerGreaterThanOrEqual,
41004112
_integerLessThanOrEqual: _integerLessThanOrEqual,
41014113
splitIntIntoMantissaExpt: splitIntIntoMantissaExpt,
4114+
getResidue: getResidue,
41024115
nbi: nbi,
41034116
integerNthRoot: integerNthRoot,
41044117
liftFixnumInteger: liftFixnumInteger,

tests/jsnums-test/jsnums-test.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,12 @@ R(["pyret-base/js/js-numbers"], function(JN) {
359359
it('other subrs', function() {
360360

361361
// toRepeatingDecimal
362-
expect(arrayEquals(JN.toRepeatingDecimal(883, 700, undefined, sampleErrbacks), ['1', '26', '142857'],
362+
expect(arrayEquals(JN.toRepeatingDecimal(883, 700, undefined, sampleErrbacks),
363+
['1', '26', '142857'],
364+
undefined, sampleErrbacks))
365+
.toBe(true);
366+
expect(arrayEquals(JN.toRepeatingDecimal(883, 700, {limit: 2}, sampleErrbacks),
367+
['1', '26', '...'],
363368
undefined, sampleErrbacks))
364369
.toBe(true);
365370
expect(function() {
@@ -380,6 +385,11 @@ R(["pyret-base/js/js-numbers"], function(JN) {
380385
JN.toRepeatingDecimal(355/133, 10, sampleErrbacks);
381386
}).toThrowError(/undefined/);
382387

388+
expect(arrayEquals(JN._innards.getResidue(183, 700, 512, sampleErrbacks), ['26', '142857']))
389+
.toBe(true);
390+
expect(arrayEquals(JN._innards.getResidue(183, 700, 2, sampleErrbacks), ['26', '...']))
391+
.toBe(true);
392+
383393
// toStringDigits
384394
expect(JN.toStringDigits(123456789, 5, sampleErrbacks))
385395
.toBe("123456789.00000");

0 commit comments

Comments
 (0)