Skip to content

Commit 68fd1dc

Browse files
committed
define sum and prod on integers, decimals and rationals, and lcm and gcd on integers
1 parent f8edf20 commit 68fd1dc

File tree

4 files changed

+172
-3
lines changed

4 files changed

+172
-3
lines changed

runtime/scripts/jme-builtins.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,8 @@ newBuiltin('root', [TNum, TNum], TNum, math.root);
10431043
newBuiltin('award', [TNum, TBool], TNum, function(a, b) {
10441044
return (b ? a : 0);
10451045
});
1046-
newBuiltin('gcd', [TNum, TNum], TNum, math.gcf);
1046+
newBuiltin('gcd', [TNum, TNum], TNum, math.gcd);
1047+
newBuiltin('gcd', [TInt, TInt], TInt, function(a,b) { return new TInt(math.gcd(a,b)); },{unwrapValues: true});
10471048
newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // take out factors of pi or i before working out gcd. Used by the fraction simplification rules
10481049
if(a.complex && a.re == 0) {
10491050
a = a.im;
@@ -1057,6 +1058,20 @@ newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // tak
10571058
});
10581059
newBuiltin('coprime', [TNum, TNum], TBool, math.coprime);
10591060
newBuiltin('lcm', [sig.multiple(sig.type('number'))], TNum, math.lcm);
1061+
newBuiltin('lcm', [sig.multiple(sig.type('integer'))], TInt, function() {
1062+
return new TInt(math.lcm.apply(math, arguments));
1063+
},{unwrapValues: true});
1064+
newBuiltin('lcm', [sig.listof(sig.type('integer'))], TInt, function(l) {
1065+
if(l.length == 0) {
1066+
return new TInt(1);
1067+
} else if(l.length == 1) {
1068+
return new TInt(l[0]);
1069+
} else {
1070+
return new TInt(math.lcm.apply(math, l));
1071+
}
1072+
},
1073+
{unwrapValues: true}
1074+
);
10601075
newBuiltin('lcm', [sig.listof(sig.type('number'))], TNum, function(l) {
10611076
if(l.length == 0) {
10621077
return 1;
@@ -1399,8 +1414,43 @@ newBuiltin('fract', [TDecimal], TDecimal, function(a) {
13991414

14001415

14011416
newBuiltin('sum', [sig.listof(sig.type('number'))], TNum, math.sum, {unwrapValues: true});
1417+
newBuiltin('sum', [sig.listof(sig.type('integer'))], TInt, function(list) {
1418+
return new TInt(math.sum(list));
1419+
}, {unwrapValues: true});
1420+
newBuiltin('sum', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
1421+
let total = math.ensure_decimal(0);
1422+
for(let x of list) {
1423+
total = total.plus(x);
1424+
}
1425+
return total;
1426+
}, {unwrapValues: true});
1427+
newBuiltin('sum', [sig.listof(sig.type('rational'))], TRational, function(list) {
1428+
let total = new Fraction(0,1);
1429+
for(let x of list) {
1430+
total = total.add(x);
1431+
}
1432+
return total;
1433+
}, {unwrapValues: true});
14021434
newBuiltin('sum', [TVector], TNum, math.sum);
1435+
14031436
newBuiltin('prod', [sig.listof(sig.type('number'))], TNum, math.prod, {unwrapValues: true});
1437+
newBuiltin('prod', [sig.listof(sig.type('integer'))], TInt, function(list) {
1438+
return new TInt(math.prod(list));
1439+
}, {unwrapValues: true});
1440+
newBuiltin('prod', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
1441+
let total = math.ensure_decimal(1);
1442+
for(let x of list) {
1443+
total = total.times(x);
1444+
}
1445+
return total;
1446+
}, {unwrapValues: true});
1447+
newBuiltin('prod', [sig.listof(sig.type('rational'))], TRational, function(list) {
1448+
let total = new Fraction(1,1);
1449+
for(let x of list) {
1450+
total = total.multiply(x);
1451+
}
1452+
return total;
1453+
}, {unwrapValues: true});
14041454
newBuiltin('prod', [TVector], TNum, math.prod);
14051455
newBuiltin('deal', [TNum], TList,
14061456
function(n) {

tests/jme-runtime.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15688,7 +15688,8 @@ newBuiltin('root', [TNum, TNum], TNum, math.root);
1568815688
newBuiltin('award', [TNum, TBool], TNum, function(a, b) {
1568915689
return (b ? a : 0);
1569015690
});
15691-
newBuiltin('gcd', [TNum, TNum], TNum, math.gcf);
15691+
newBuiltin('gcd', [TNum, TNum], TNum, math.gcd);
15692+
newBuiltin('gcd', [TInt, TInt], TInt, function(a,b) { return new TInt(math.gcd(a,b)); },{unwrapValues: true});
1569215693
newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // take out factors of pi or i before working out gcd. Used by the fraction simplification rules
1569315694
if(a.complex && a.re == 0) {
1569415695
a = a.im;
@@ -15702,6 +15703,20 @@ newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // tak
1570215703
});
1570315704
newBuiltin('coprime', [TNum, TNum], TBool, math.coprime);
1570415705
newBuiltin('lcm', [sig.multiple(sig.type('number'))], TNum, math.lcm);
15706+
newBuiltin('lcm', [sig.multiple(sig.type('integer'))], TInt, function() {
15707+
return new TInt(math.lcm.apply(math, arguments));
15708+
},{unwrapValues: true});
15709+
newBuiltin('lcm', [sig.listof(sig.type('integer'))], TInt, function(l) {
15710+
if(l.length == 0) {
15711+
return new TInt(1);
15712+
} else if(l.length == 1) {
15713+
return new TInt(l[0]);
15714+
} else {
15715+
return new TInt(math.lcm.apply(math, l));
15716+
}
15717+
},
15718+
{unwrapValues: true}
15719+
);
1570515720
newBuiltin('lcm', [sig.listof(sig.type('number'))], TNum, function(l) {
1570615721
if(l.length == 0) {
1570715722
return 1;
@@ -16044,8 +16059,43 @@ newBuiltin('fract', [TDecimal], TDecimal, function(a) {
1604416059

1604516060

1604616061
newBuiltin('sum', [sig.listof(sig.type('number'))], TNum, math.sum, {unwrapValues: true});
16062+
newBuiltin('sum', [sig.listof(sig.type('integer'))], TInt, function(list) {
16063+
return new TInt(math.sum(list));
16064+
}, {unwrapValues: true});
16065+
newBuiltin('sum', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
16066+
let total = math.ensure_decimal(0);
16067+
for(let x of list) {
16068+
total = total.plus(x);
16069+
}
16070+
return total;
16071+
}, {unwrapValues: true});
16072+
newBuiltin('sum', [sig.listof(sig.type('rational'))], TRational, function(list) {
16073+
let total = new Fraction(0,1);
16074+
for(let x of list) {
16075+
total = total.add(x);
16076+
}
16077+
return total;
16078+
}, {unwrapValues: true});
1604716079
newBuiltin('sum', [TVector], TNum, math.sum);
16080+
1604816081
newBuiltin('prod', [sig.listof(sig.type('number'))], TNum, math.prod, {unwrapValues: true});
16082+
newBuiltin('prod', [sig.listof(sig.type('integer'))], TInt, function(list) {
16083+
return new TInt(math.prod(list));
16084+
}, {unwrapValues: true});
16085+
newBuiltin('prod', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
16086+
let total = math.ensure_decimal(1);
16087+
for(let x of list) {
16088+
total = total.times(x);
16089+
}
16090+
return total;
16091+
}, {unwrapValues: true});
16092+
newBuiltin('prod', [sig.listof(sig.type('rational'))], TRational, function(list) {
16093+
let total = new Fraction(1,1);
16094+
for(let x of list) {
16095+
total = total.multiply(x);
16096+
}
16097+
return total;
16098+
}, {unwrapValues: true});
1604916099
newBuiltin('prod', [TVector], TNum, math.prod);
1605016100
newBuiltin('deal', [TNum], TList,
1605116101
function(n) {

tests/jme/jme-tests.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,9 @@ Numbas.queueScript('jme_tests',['qunit','jme','jme-rules','jme-display','jme-cal
900900
raisesNumbasError(assert, function() {evaluate('comb(1,i)')},'math.combinations.complex',"error: can't compute combinations of complex numbers: comb(1,i)");
901901

902902
closeEqual(assert, evaluate('gcd(36,15)').value,3,'gcd(36,15)');
903+
closeEqual(assert, evaluate('gcd(36,15)').type,'integer','gcd(36,15) returns an integer');
903904
closeEqual(assert, evaluate('gcd(1.1,15)').value,1,'gcd(1.1,15)');
905+
closeEqual(assert, evaluate('gcd(1.1,15)').type,'number','gcd(1.1,15) returns a number');
904906
closeEqual(assert, evaluate('gcd(-60,18)').value,6,'gcd(-60,18)');
905907
closeEqual(assert, evaluate('gcd(60,-18)').value,6,'gcd(60,-18)');
906908
closeEqual(assert, evaluate('gcd(0,3)').value,3,'gcd(0,3)');
@@ -918,6 +920,8 @@ Numbas.queueScript('jme_tests',['qunit','jme','jme-rules','jme-display','jme-cal
918920
closeEqual(assert, evaluate('coprime(1,1)').value,true,'coprime(1,1)');
919921

920922
closeEqual(assert, evaluate('lcm(3,7)').value,21,'lcm(3,7)');
923+
closeEqual(assert, evaluate('lcm(3,7)').type, 'integer','lcm(3,7) returns an integer');
924+
closeEqual(assert, evaluate('lcm([3,7,9])').type, 'integer','lcm([3,7,9]) returns an integer');
921925
closeEqual(assert, evaluate('lcm(4,6)').value,12,'lcm(4,12)');
922926
closeEqual(assert, evaluate('lcm(-10,35)').value,70,'lcm(-10,35)');
923927
raisesNumbasError(assert, function(){ evaluate('lcm(2,i)') },'math.lcm.complex',"can't find lcm of complex numbers: lcm(2,i)");
@@ -1381,9 +1385,24 @@ Numbas.queueScript('jme_tests',['qunit','jme','jme-rules','jme-display','jme-cal
13811385
raisesNumbasError(assert, function() { evaluate('dict(["a",1])'); }, 'jme.typecheck.no right type definition','dict(["a",1])');
13821386

13831387
assert.equal(evaluate('sum([])').value,0,'sum([])');
1388+
assert.equal(evaluate('sum([])').type,'number','sum([]) returns a number');
13841389
assert.equal(evaluate('sum([1,2,3])').value,6,'sum([1,2,3])');
1390+
assert.equal(evaluate('sum([1,2,3])').type,'integer','sum([1,2,3]) returns an integer');
1391+
assert.equal(evaluate('sum([1.1,2,3])').type,'number','sum([1.1,2,3]) returns a number');
1392+
assert.equal(evaluate('sum([dec(1), pi])').type,'decimal','sum([dec(1), pi]) returns a decimal');
1393+
assert.equal(evaluate('sum([1/2, 3/4])').value.toString(), '5/4','sum([1/2, 3/4])');
1394+
assert.equal(evaluate('sum([1/2, 3/4])').type,'rational','sum([1/2, 3/4]) returns a rational');
1395+
assert.equal(evaluate('sum([1, 1/2, dec(3)])').type,'decimal','sum([1, 1/2, dec(3)]) returns a decimal');
1396+
assert.equal(evaluate('sum([1, 1/2, dec(3), 1.1])').type,'decimal','sum([1, 1/2, dec(3), 1.1]) returns a number');
13851397
assert.equal(evaluate('prod([])').value,1,'prod([])');
13861398
assert.equal(evaluate('prod([2,3,4])').value,24,'prod([2,3,4])');
1399+
assert.equal(evaluate('prod([2,3,4])').type, 'integer', 'prod([2,3,4]) returns an integer');
1400+
assert.equal(evaluate('prod([2.1,3,4])').type, 'number', 'prod([2.1,3,4]) returns a number');
1401+
assert.equal(evaluate('prod([dec(2), pi])').type, 'decimal', 'prod([dec(2), pi]) returns a decimal');
1402+
assert.equal(evaluate('prod([1/2, 3/4])').value.toString(),'3/8','prod([1/2, 3/4])');
1403+
assert.equal(evaluate('prod([1/2, 3/4])').type,'rational','prod([1/2, 3/4]) returns a rational');
1404+
assert.equal(evaluate('prod([1, 1/2, dec(3)])').type,'decimal','prod([1, 1/2, dec(3)]) returns a decimal');
1405+
assert.equal(evaluate('prod([1, 1/2, dec(3), 1.1])').type,'decimal','prod([1, 1/2, dec(3), 1.1]) returns a number');
13871406
raisesNumbasError(assert, function() { evaluate('sum(["a","b"])') },'jme.typecheck.no right type definition','sum(["a","b"])');
13881407

13891408
deepCloseEqual(assert, jme.unwrapValue(evaluate('transpose([[1,2],[3,4,5]])')), [[1,3],[2,4]], 'transpose([[1,2],[3,4,5]])');

tests/numbas-runtime.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15024,7 +15024,8 @@ newBuiltin('root', [TNum, TNum], TNum, math.root);
1502415024
newBuiltin('award', [TNum, TBool], TNum, function(a, b) {
1502515025
return (b ? a : 0);
1502615026
});
15027-
newBuiltin('gcd', [TNum, TNum], TNum, math.gcf);
15027+
newBuiltin('gcd', [TNum, TNum], TNum, math.gcd);
15028+
newBuiltin('gcd', [TInt, TInt], TInt, function(a,b) { return new TInt(math.gcd(a,b)); },{unwrapValues: true});
1502815029
newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // take out factors of pi or i before working out gcd. Used by the fraction simplification rules
1502915030
if(a.complex && a.re == 0) {
1503015031
a = a.im;
@@ -15038,6 +15039,20 @@ newBuiltin('gcd_without_pi_or_i', [TNum, TNum], TNum, function(a, b) { // tak
1503815039
});
1503915040
newBuiltin('coprime', [TNum, TNum], TBool, math.coprime);
1504015041
newBuiltin('lcm', [sig.multiple(sig.type('number'))], TNum, math.lcm);
15042+
newBuiltin('lcm', [sig.multiple(sig.type('integer'))], TInt, function() {
15043+
return new TInt(math.lcm.apply(math, arguments));
15044+
},{unwrapValues: true});
15045+
newBuiltin('lcm', [sig.listof(sig.type('integer'))], TInt, function(l) {
15046+
if(l.length == 0) {
15047+
return new TInt(1);
15048+
} else if(l.length == 1) {
15049+
return new TInt(l[0]);
15050+
} else {
15051+
return new TInt(math.lcm.apply(math, l));
15052+
}
15053+
},
15054+
{unwrapValues: true}
15055+
);
1504115056
newBuiltin('lcm', [sig.listof(sig.type('number'))], TNum, function(l) {
1504215057
if(l.length == 0) {
1504315058
return 1;
@@ -15380,8 +15395,43 @@ newBuiltin('fract', [TDecimal], TDecimal, function(a) {
1538015395

1538115396

1538215397
newBuiltin('sum', [sig.listof(sig.type('number'))], TNum, math.sum, {unwrapValues: true});
15398+
newBuiltin('sum', [sig.listof(sig.type('integer'))], TInt, function(list) {
15399+
return new TInt(math.sum(list));
15400+
}, {unwrapValues: true});
15401+
newBuiltin('sum', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
15402+
let total = math.ensure_decimal(0);
15403+
for(let x of list) {
15404+
total = total.plus(x);
15405+
}
15406+
return total;
15407+
}, {unwrapValues: true});
15408+
newBuiltin('sum', [sig.listof(sig.type('rational'))], TRational, function(list) {
15409+
let total = new Fraction(0,1);
15410+
for(let x of list) {
15411+
total = total.add(x);
15412+
}
15413+
return total;
15414+
}, {unwrapValues: true});
1538315415
newBuiltin('sum', [TVector], TNum, math.sum);
15416+
1538415417
newBuiltin('prod', [sig.listof(sig.type('number'))], TNum, math.prod, {unwrapValues: true});
15418+
newBuiltin('prod', [sig.listof(sig.type('integer'))], TInt, function(list) {
15419+
return new TInt(math.prod(list));
15420+
}, {unwrapValues: true});
15421+
newBuiltin('prod', [sig.listof(sig.type('decimal'))], TDecimal, function(list) {
15422+
let total = math.ensure_decimal(1);
15423+
for(let x of list) {
15424+
total = total.times(x);
15425+
}
15426+
return total;
15427+
}, {unwrapValues: true});
15428+
newBuiltin('prod', [sig.listof(sig.type('rational'))], TRational, function(list) {
15429+
let total = new Fraction(1,1);
15430+
for(let x of list) {
15431+
total = total.multiply(x);
15432+
}
15433+
return total;
15434+
}, {unwrapValues: true});
1538515435
newBuiltin('prod', [TVector], TNum, math.prod);
1538615436
newBuiltin('deal', [TNum], TList,
1538715437
function(n) {

0 commit comments

Comments
 (0)