11

In Javascript: Math.max and Math.min do not work for BigInt types.

For example:

> Math.max(1n, 2n)
Thrown:
TypeError: Cannot convert a BigInt value to a number
    at Math.max (<anonymous>)
>

Is there a built in function that performs these operations on BigInts?

2 Answers2

9

how about

const bigIntMax = (...args) => args.reduce((m, e) => e > m ? e : m);
const bigIntMin = (...args) => args.reduce((m, e) => e < m ? e : m);

also if you want both then

const bigIntMinAndMax = (...args) => {
  return args.reduce(([min,max], e) => {
     return [
       e < min ? e : min, 
       e > max ? e : max,
     ];
  }, [args[0], args[0]]);
};

const [min, max] = bigIntMinAndMax(
   BigInt(40),
   BigInt(50),
   BigInt(30),
   BigInt(10),
   BigInt(20),
);
gman
  • 100,619
  • 31
  • 269
  • 393
  • sort should be slower since it requires at least N but usually more than N operations. Plus it's destructive meaning I might want the min but I don't want the order of my array changed – gman Apr 20 '20 at 14:24
  • 1
    After testing my answer versus your answer for performance, I found that your medthod (with reduce) is about 25,000x faster – Lex - Boycott Slack - see bio Apr 20 '20 at 14:32
  • I'm not so sure that returning +/-Infinity is ever useful, since they aren't of the BigInt type. It means that the error of using an empty list will be caught much later when you find you don't have a BigInt like you thought you did. – Lex - Boycott Slack - see bio Apr 20 '20 at 14:36
  • Got rid of the infinity. But yes, it doesn't catch an error. Neither does Math.min or Math.max though but you can add error checking if you want. You shouldn't be asking for min or max of an empty list in the first place as there is no correct answer. – gman Apr 20 '20 at 14:45
2

After some googleing it looks like the answer is no, Javascript has no builtin functions for this.

Here is an implementation of min and max for bigints that matches the signature of the built in ones, except that it throws errors for empty lists (instead of returning +/-Infinity, as BigInt can't represent infinity):

function bigint_min(...args){
    if (args.length < 1){ throw 'Min of empty list'; }
    m = args[0];
    args.forEach(a=>{if (a < m) {m = a}});
    return m;
}

function bigint_max(...args){
    if (args.length < 1){ throw 'Max of empty list'; }
    m = args[0];
    args.forEach(a=>{if (a > m) {m = a}});
    return m;
}
  • `args.reduce( (min, val) => min > val ? val : min, Infinity );` might be a bit more readable. – Kaiido Apr 20 '20 at 14:15
  • @Kaiido Agreed, reduce is more readable, but Infinity is of Number type, and can't be represented by a BigInt type. – Lex - Boycott Slack - see bio Apr 20 '20 at 14:34
  • Isn't Infinity still bigger than any bigInt? – Kaiido Apr 20 '20 at 14:36
  • Yes, it is, but it means that the function would return either `BigInt()` or `Number('Infinity')`. So the return type is not consistent, whereas the builtin min and max always return the same type (the `Number` type) – Lex - Boycott Slack - see bio Apr 20 '20 at 14:38
  • Since you do the check for args.length<1 and that nothing except Infinity is as big or bigger than Infinity, the only way it returns Infinity is by passing Infinity. – Kaiido Apr 20 '20 at 14:41
  • Ah I see what you mean now, yeah you're right. I was thinking of a situation more like the first part of @gman's answer, where no explicit check is done. It's interesting that JS actually defines `<` and `>` for a mix of BigInt and Number, but doesn't define many other operations on the same mix. – Lex - Boycott Slack - see bio Apr 20 '20 at 14:45