From 3497f369931d7641122c4b4178cf9129edcc678f Mon Sep 17 00:00:00 2001 From: "Amy J. Ko" Date: Sat, 13 Jul 2024 10:57:21 -0700 Subject: [PATCH] Changed value of divide by zero to non-a-number; defined not-a-number literal. --- CHANGELOG.md | 1 + src/parser/Tokenizer.test.ts | 2 +- src/parser/Tokenizer.ts | 1 + src/values/NumberValue.test.ts | 2 +- src/values/NumberValue.ts | 82 +++++++++++++++++----------------- 5 files changed, 46 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58371e851..261a2e975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Dates are in `YYYY-MM-DD` format and versions are in [semantic versioning](http: - Permit comma separators between text literals, docs, and names, allowing line breaks for text. - Define `Input`s corresponding definition to enable code localization. - Improved `MissingInput` conflict. +- Changed value of divide by zero to non-a-number; defined not-a-number literal. ## 0.10.4 2024-07-08 diff --git a/src/parser/Tokenizer.test.ts b/src/parser/Tokenizer.test.ts index c2e00753f..4a6859663 100644 --- a/src/parser/Tokenizer.test.ts +++ b/src/parser/Tokenizer.test.ts @@ -14,7 +14,7 @@ test.each([ ['1,0', '1,0|'], ['0.5', '0.5|'], ['.5', '.5|'], - ['0∞π', '0|∞|π|'], + ['0∞π!#', '0|∞|π|!#|'], ['🌏🌍🌎', '🌏|🌍|🌎|'], [ '一 十 百 百一 百四十五 百九十九 千一 万十一 万', diff --git a/src/parser/Tokenizer.ts b/src/parser/Tokenizer.ts index 8b768cd5c..ea768550b 100644 --- a/src/parser/Tokenizer.ts +++ b/src/parser/Tokenizer.ts @@ -185,6 +185,7 @@ const CodeTokenPatterns: TokenPattern[] = [ { pattern: CONVERT_SYMBOL3, types: [Sym.Convert] }, { pattern: NONE_SYMBOL, types: [Sym.None, Sym.None] }, { pattern: TYPE_SYMBOL, types: [Sym.Type, Sym.TypeOperator] }, + { pattern: /^!#/, types: [Sym.Number] }, { pattern: LITERAL_SYMBOL, types: [Sym.Literal] }, { pattern: OR_SYMBOL, diff --git a/src/values/NumberValue.test.ts b/src/values/NumberValue.test.ts index 1b3c3292d..2f7c56a7a 100644 --- a/src/values/NumberValue.test.ts +++ b/src/values/NumberValue.test.ts @@ -75,7 +75,7 @@ test.each([ ['1 · 0', '0'], ['1 ÷ 1', '1'], ['0 ÷ 1', '0'], - ['1 ÷ 0', 'ø'], + ['1 ÷ 0', '!#'], ['10 ÷ 5', '2'], ['-10 ÷ -5', '2'], ['1 ÷ 3', '0.33333333333333333333'], diff --git a/src/values/NumberValue.ts b/src/values/NumberValue.ts index de557cc9e..3e4aa1a8a 100644 --- a/src/values/NumberValue.ts +++ b/src/values/NumberValue.ts @@ -25,7 +25,7 @@ export default class NumberValue extends SimpleValue { creator: Expression, number: number | Token | Decimal | string, unit?: Unit, - precision?: number + precision?: number, ) { super(creator); @@ -68,8 +68,10 @@ export default class NumberValue extends SimpleValue { const negated = text.charAt(0) === '-'; if (negated) text = text.substring(1); + // Not a number + if (text === '!#') return [new Decimal(NaN), undefined]; // Infinity - if (number.isSymbol(Sym.Infinity) || text === '∞') { + else if (number.isSymbol(Sym.Infinity) || text === '∞') { return [new Decimal(Infinity * (negated ? -1 : 1)), undefined]; } // Pi @@ -126,7 +128,7 @@ export default class NumberValue extends SimpleValue { return new NumberValue( requestor, this.num.pow(new Decimal(1).div(operand.num)), - this.unit.root(operand.num.toNumber()) + this.unit.root(operand.num.toNumber()), ); } @@ -154,33 +156,33 @@ export default class NumberValue extends SimpleValue { return new NumberValue( requestor, this.num.times(operand.num), - this.unit.product(operand.unit) + this.unit.product(operand.unit), ); } divide( requestor: Expression, - divisor: NumberValue + divisor: NumberValue, ): NumberValue | NoneValue { return divisor.num.isZero() - ? new NoneValue(requestor) + ? new NumberValue(requestor, new Decimal(NaN)) : new NumberValue( requestor, this.num.dividedBy(divisor.num), - this.unit.quotient(divisor.unit) + this.unit.quotient(divisor.unit), ); } remainder( requestor: Expression, - divisor: NumberValue + divisor: NumberValue, ): NumberValue | NoneValue { return divisor.num.isZero() ? new NoneValue(requestor) : new NumberValue( requestor, this.num.modulo(divisor.num), - this.unit + this.unit, ); } @@ -204,14 +206,14 @@ export default class NumberValue extends SimpleValue { return new BoolValue( requestor, this.num.greaterThan(operand.num) && - this.unit.isEqualTo(operand.unit) + this.unit.isEqualTo(operand.unit), ); } lessThan(requestor: Expression, operand: NumberValue): BoolValue { return new BoolValue( requestor, - this.num.lessThan(operand.num) && this.unit.isEqualTo(operand.unit) + this.num.lessThan(operand.num) && this.unit.isEqualTo(operand.unit), ); } @@ -219,7 +221,7 @@ export default class NumberValue extends SimpleValue { return new NumberValue( requestor, this.num.pow(operand.num), - this.unit.power(operand.num.toNumber()) + this.unit.power(operand.num.toNumber()), ); } @@ -248,15 +250,15 @@ export default class NumberValue extends SimpleValue { this.num.isNaN() ? '!#' : !this.num.isFinite() - ? `${this.num.isPositive() ? '' : '-'}∞` - : this.num.toString() + ? `${this.num.isPositive() ? '' : '-'}∞` + : this.num.toString() }${this.unit.toString()}`; } getDescription(concretize: Concretizer, locales: Locales) { return concretize( locales, - locales.get((l) => l.term.number) + locales.get((l) => l.term.number), ); } @@ -322,7 +324,7 @@ function convertBase(text: string, negated: boolean): NumberAndPrecision { while (text.indexOf('_') >= 0) text = text.replace( '_', - Decimal.random().times(base).floor().toString() + Decimal.random().times(base).floor().toString(), ); const [integral, fractional] = text.split('.'); @@ -332,16 +334,16 @@ function convertBase(text: string, negated: boolean): NumberAndPrecision { d === 'A' ? 10 : d === 'B' - ? 11 - : d === 'C' - ? 12 - : d === 'D' - ? 13 - : d === 'E' - ? 14 - : d === 'F' - ? 15 - : parseInt(d) + ? 11 + : d === 'C' + ? 12 + : d === 'D' + ? 13 + : d === 'E' + ? 14 + : d === 'F' + ? 15 + : parseInt(d), ); if (integralDigits.find((d) => d >= base) !== undefined) { return [new Decimal(NaN), undefined]; @@ -352,8 +354,8 @@ function convertBase(text: string, negated: boolean): NumberAndPrecision { const digit = integralDigits.pop() as number; num = num.plus( new Decimal(digit).times( - new Decimal(base).pow(new Decimal(position)) - ) + new Decimal(base).pow(new Decimal(position)), + ), ); position++; } @@ -366,23 +368,23 @@ function convertBase(text: string, negated: boolean): NumberAndPrecision { d === 'A' ? 10 : d === 'B' - ? 11 - : d === 'C' - ? 12 - : d === 'D' - ? 13 - : d === 'E' - ? 14 - : d === 'F' - ? 15 - : parseInt(d) + ? 11 + : d === 'C' + ? 12 + : d === 'D' + ? 13 + : d === 'E' + ? 14 + : d === 'F' + ? 15 + : parseInt(d), ); while (fractionalDigits.length > 0) { const digit = fractionalDigits.shift() as number; num = num.plus( new Decimal(digit).times( - new Decimal(base).pow(new Decimal(position).neg()) - ) + new Decimal(base).pow(new Decimal(position).neg()), + ), ); position++; }