2020-01-19 release

This commit is contained in:
bellard 2020-09-06 18:57:11 +02:00
parent 91459fb672
commit 0e8fffd4de
26 changed files with 4298 additions and 3639 deletions

View File

@ -1,3 +1,15 @@
2020-01-19:
- keep CONFIG_BIGNUM in the makefile
- added os.chdir()
- qjs: added -I option
- more memory checks in the bignum operations
- modified operator overloading semantics to be closer to the TC39
proposal
- suppressed "use bigint" mode. Simplified "use math" mode
- BigDecimal: changed suffix from 'd' to 'm'
- misc bug fixes
2020-01-05:
- always compile the bignum code. Added '--bignum' option to qjs.

View File

@ -1,8 +1,8 @@
#
# QuickJS Javascript Engine
#
# Copyright (c) 2017-2019 Fabrice Bellard
# Copyright (c) 2017-2019 Charlie Gordon
# Copyright (c) 2017-2020 Fabrice Bellard
# Copyright (c) 2017-2020 Charlie Gordon
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -47,6 +47,8 @@ prefix=/usr/local
#CONFIG_PROFILE=y
# use address sanitizer
#CONFIG_ASAN=y
# include the code for BigInt/BigFloat/BigDecimal and math mode
CONFIG_BIGNUM=y
OBJDIR=.obj
@ -94,6 +96,9 @@ ifdef CONFIG_WERROR
CFLAGS+=-Werror
endif
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
ifdef CONFIG_BIGNUM
DEFINES+=-DCONFIG_BIGNUM
endif
CFLAGS+=$(DEFINES)
CFLAGS_DEBUG=$(CFLAGS) -O0
CFLAGS_SMALL=$(CFLAGS) -Os
@ -153,9 +158,13 @@ endif
all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/libbf.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(OBJDIR)/qjscalc.o $(QJS_LIB_OBJS)
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
ifdef CONFIG_BIGNUM
QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
QJS_OBJS+=$(OBJDIR)/qjscalc.o
endif
LIBS=-lm
ifndef CONFIG_WIN32
@ -301,7 +310,10 @@ endif
HELLO_SRCS=examples/hello.js
HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
-fno-date -fno-module-loader -fno-bigint
-fno-date -fno-module-loader
ifdef CONFIG_BIGNUM
HELLO_OPTS+=-fno-bigint
endif
hello.c: $(QJSC) $(HELLO_SRCS)
$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
@ -372,20 +384,30 @@ test: qjs
./qjs tests/test_loop.js
./qjs tests/test_std.js
ifndef CONFIG_DARWIN
ifdef CONFIG_BIGNUM
./qjs --bignum tests/test_bjson.js
else
./qjs tests/test_bjson.js
endif
./qjs examples/test_point.js
endif
ifdef CONFIG_BIGNUM
./qjs --bignum tests/test_op_overloading.js
./qjs --bignum tests/test_bignum.js
./qjs --qjscalc tests/test_qjscalc.js
endif
ifdef CONFIG_M32
./qjs32 tests/test_closure.js
./qjs32 tests/test_op.js
./qjs32 tests/test_builtin.js
./qjs32 tests/test_loop.js
./qjs32 tests/test_std.js
ifdef CONFIG_BIGNUM
./qjs32 --bignum tests/test_op_overloading.js
./qjs32 --bignum tests/test_bignum.js
./qjs32 --qjscalc tests/test_qjscalc.js
endif
endif
stats: qjs qjs32
./qjs -qd

5
TODO
View File

@ -73,6 +73,5 @@ REPL:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Test262: 4/67619 errors, 913 excluded, 1660 skipped
Test262bn: 4/69722 errors, 846 excluded, 672 skipped
test262 commit: 19fd4bea797646ae9bbfc9d325f14052ca370b54
Test262: 17/69942 errors, 855 excluded, 581 skipped
test262 commit: 28b4fcca4b1b1d278dfe0cc0e69c7d9d59b31aab

View File

@ -1 +1 @@
2020-01-05
2020-01-19

View File

@ -1,7 +1,8 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Javascript Bignum Extensions</title>
<meta name="description" content="Javascript Bignum Extensions">
@ -9,7 +10,6 @@
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
@ -52,61 +52,33 @@ ul.no-bullet {list-style: none}
<div class="contents">
<ul class="no-bullet">
<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a>
<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
<ul class="no-bullet">
<li><a name="toc-Introduction-1" href="#Introduction-1">2.1 Introduction</a></li>
<li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">2.2 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-Symbol-constructor" href="#Symbol-constructor">2.2.1 <code>Symbol</code> constructor</a></li>
</ul></li>
</ul></li>
<li><a name="toc-The-BigInt-Mode" href="#The-BigInt-Mode">3 The BigInt Mode</a>
<ul class="no-bullet">
<li><a name="toc-Introduction-2" href="#Introduction-2">3.1 Introduction</a></li>
<li><a name="toc-Changes-that-introduce-incompatibilities-with-Javascript" href="#Changes-that-introduce-incompatibilities-with-Javascript">3.2 Changes that introduce incompatibilities with Javascript</a>
<ul class="no-bullet">
<li><a name="toc-Standard-mode" href="#Standard-mode">3.2.1 Standard mode</a></li>
<li><a name="toc-Bigint-mode" href="#Bigint-mode">3.2.2 Bigint mode</a></li>
</ul></li>
<li><a name="toc-Operators" href="#Operators">3.3 Operators</a>
<ul class="no-bullet">
<li><a name="toc-Arithmetic-operators" href="#Arithmetic-operators">3.3.1 Arithmetic operators</a></li>
<li><a name="toc-Logical-operators" href="#Logical-operators">3.3.2 Logical operators</a></li>
<li><a name="toc-Relational-operators" href="#Relational-operators">3.3.3 Relational operators</a></li>
</ul></li>
<li><a name="toc-Number-literals" href="#Number-literals">3.4 Number literals</a></li>
<li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">3.5 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-BigInt-function" href="#BigInt-function">3.5.1 <code>BigInt</code> function</a></li>
<li><a name="toc-BigInt_002eprototype" href="#BigInt_002eprototype">3.5.2 <code>BigInt.prototype</code></a></li>
<li><a name="toc-Number-constructor" href="#Number-constructor">3.5.3 <code>Number</code> constructor</a></li>
<li><a name="toc-Number_002eprototype" href="#Number_002eprototype">3.5.4 <code>Number.prototype</code></a></li>
<li><a name="toc-Math-object" href="#Math-object">3.5.5 <code>Math</code> object</a></li>
</ul></li>
</ul></li>
<li><a name="toc-Arbitrarily-large-floating-point-numbers" href="#Arbitrarily-large-floating-point-numbers">4 Arbitrarily large floating point numbers</a>
<ul class="no-bullet">
<li><a name="toc-Introduction-3" href="#Introduction-3">4.1 Introduction</a></li>
<li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
<li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
<li><a name="toc-Operators-1" href="#Operators-1">4.3 Operators</a></li>
<li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
<li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
<li><a name="toc-Builtin-Object-changes-2" href="#Builtin-Object-changes-2">4.5 Builtin Object changes</a>
<li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
<li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
<li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
<li><a name="toc-Math-object-1" href="#Math-object-1">4.5.4 <code>Math</code> object</a></li>
</ul></li>
</ul></li>
<li><a name="toc-Math-mode" href="#Math-mode">5 Math mode</a>
<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
<ul class="no-bullet">
<li><a name="toc-Introduction-4" href="#Introduction-4">5.1 Introduction</a></li>
<li><a name="toc-Builtin-Object-changes-3" href="#Builtin-Object-changes-3">5.2 Builtin Object changes</a>
<li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
<li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
<li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-Symbol-constructor-1" href="#Symbol-constructor-1">5.2.1 <code>Symbol</code> constructor</a></li>
<li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
<li><a name="toc-Properties-of-the-BigDecimal-object" href="#Properties-of-the-BigDecimal-object">5.3.2 Properties of the <code>BigDecimal</code> object</a></li>
<li><a name="toc-Properties-of-the-BigDecimal_002eprototype-object" href="#Properties-of-the-BigDecimal_002eprototype-object">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</a></li>
</ul></li>
<li><a name="toc-Remaining-issues" href="#Remaining-issues">5.3 Remaining issues</a></li>
</ul></li>
<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
</ul>
</div>
@ -119,379 +91,52 @@ ul.no-bullet {list-style: none}
language while being 100% backward compatible:
</p>
<ul>
<li> Overloading of the standard operators
to support new types such as complex numbers, fractions or matrices.
</li><li> Bigint mode where arbitrarily large integers are available by default (no <code>n</code> suffix is necessary as in the TC39 BigInt proposal<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>).
<li> Operator overloading with a dispatch logic inspired from the proposal available at <a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>.
</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
</li><li> Optional <code>math</code> mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
</li><li> <code>math</code> mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (<code>%</code>) is defined as the Euclidian
remainder. <code>^</code> is an alias to the power operator
(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
</li></ul>
<p>The extensions are independent from each other except the <code>math</code>
mode which relies on the bigint mode and the operator overloading.
mode which relies on BigFloat and operator overloading.
</p>
<a name="Operator-overloading"></a>
<h2 class="chapter">2 Operator overloading</h2>
<a name="Introduction-1"></a>
<h3 class="section">2.1 Introduction</h3>
<p>If the operands of an operator have at least one object type, a custom
operator method is searched before doing the legacy Javascript
<code>ToNumber</code> conversion.
<p>Operator overloading is inspired from the proposal available at
<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
implements the same dispatch logic but finds the operator sets by
looking at the <code>Symbol.operatorSet</code> property in the objects. The
changes were done in order to simplify the implementation.
</p>
<p>For unary operators, the custom function is looked up in the object
and has the following name:
</p>
<dl compact="compact">
<dt><code>unary +</code></dt>
<dd><p><code>Symbol.operatorPlus</code>
</p>
</dd>
<dt><code>unary -</code></dt>
<dd><p><code>Symbol.operatorNeg</code>
</p>
</dd>
<dt><code>++</code></dt>
<dd><p><code>Symbol.operatorInc</code>
</p>
</dd>
<dt><code>--</code></dt>
<dd><p><code>Symbol.operatorDec</code>
</p>
</dd>
<dt><code>~</code></dt>
<dd><p><code>Symbol.operatorNot</code>
</p>
</dd>
</dl>
<p>For binary operators:
<p>More precisely, the following modifications were made:
</p>
<ul>
<li> If both operands have the same constructor function, then the operator
is looked up in the constructor.
<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
</li><li> Otherwise, the property <code>Symbol.operatorOrder</code> is looked up in both
constructors and converted to <code>Int32</code>. The operator is then
looked in the constructor with the larger <code>Symbol.operatorOrder</code>
value. A <code>TypeError</code> is raised if both constructors have the same
<code>Symbol.operatorOrder</code> value.
</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup the of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
</li><li> <code>Operators.create(...dictionaries)</code> is used to create a new OperatorSet object. The <code>Operators</code> function is supported as an helper to be closer to the TC39 proposal.
</li><li> <code>[]</code> cannot be overloaded.
</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
</li></ul>
<p>The operator is looked up with the following name:
<a name="BigInt-extensions"></a>
<h2 class="chapter">3 BigInt extensions</h2>
<p>A few properties are added to the BigInt object:
</p>
<dl compact="compact">
<dt><code>+</code></dt>
<dd><p><code>Symbol.operatorAdd</code>
</p>
</dd>
<dt><code>-</code></dt>
<dd><p><code>Symbol.operatorSub</code>
</p>
</dd>
<dt><code>*</code></dt>
<dd><p><code>Symbol.operatorMul</code>
</p>
</dd>
<dt><code>/</code></dt>
<dd><p><code>Symbol.operatorDiv</code>
</p>
</dd>
<dt><code>%</code></dt>
<dd><p><code>Symbol.operatorMod</code>
</p>
</dd>
<dt><code>% (math mode)</code></dt>
<dd><p><code>Symbol.operatorMathMod</code>
</p>
</dd>
<dt><code>**</code></dt>
<dd><p><code>Symbol.operatorPow</code>
</p>
</dd>
<dt><code>|</code></dt>
<dd><p><code>Symbol.operatorOr</code>
</p>
</dd>
<dt><code>^</code></dt>
<dd><p><code>Symbol.operatorXor</code>
</p>
</dd>
<dt><code>&amp;</code></dt>
<dd><p><code>Symbol.operatorAnd</code>
</p>
</dd>
<dt><code>&lt;&lt;</code></dt>
<dd><p><code>Symbol.operatorShl</code>
</p>
</dd>
<dt><code>&gt;&gt;</code></dt>
<dd><p><code>Symbol.operatorShr</code>
</p>
</dd>
<dt><code>&lt;</code></dt>
<dd><p><code>Symbol.operatorCmpLT</code>
</p>
</dd>
<dt><code>&gt;</code></dt>
<dd><p><code>Symbol.operatorCmpLT</code>, operands swapped
</p>
</dd>
<dt><code>&lt;=</code></dt>
<dd><p><code>Symbol.operatorCmpLE</code>
</p>
</dd>
<dt><code>&gt;=</code></dt>
<dd><p><code>Symbol.operatorCmpLE</code>, operands swapped
</p>
</dd>
<dt><code>==, !=</code></dt>
<dd><p><code>Symbol.operatorCmpEQ</code>
</p>
</dd>
</dl>
<p>The return value of <code>Symbol.operatorCmpLT</code>, <code>Symbol.operatorCmpLE</code> and
<code>Symbol.operatorCmpEQ</code> is converted to <code>Boolean</code>.
</p>
<a name="Builtin-Object-changes"></a>
<h3 class="section">2.2 Builtin Object changes</h3>
<a name="Symbol-constructor"></a>
<h4 class="subsection">2.2.1 <code>Symbol</code> constructor</h4>
<p>The following global symbols are added for the operator overloading:
</p><dl compact="compact">
<dt><code>operatorOrder</code></dt>
<dt><code>operatorAdd</code></dt>
<dt><code>operatorSub</code></dt>
<dt><code>operatorMul</code></dt>
<dt><code>operatorDiv</code></dt>
<dt><code>operatorMod</code></dt>
<dt><code>operatorPow</code></dt>
<dt><code>operatorShl</code></dt>
<dt><code>operatorShr</code></dt>
<dt><code>operatorAnd</code></dt>
<dt><code>operatorOr</code></dt>
<dt><code>operatorXor</code></dt>
<dt><code>operatorCmpLT</code></dt>
<dt><code>operatorCmpLE</code></dt>
<dt><code>operatorCmpEQ</code></dt>
<dt><code>operatorPlus</code></dt>
<dt><code>operatorNeg</code></dt>
<dt><code>operatorNot</code></dt>
<dt><code>operatorInc</code></dt>
<dt><code>operatorDec</code></dt>
</dl>
<a name="The-BigInt-Mode"></a>
<h2 class="chapter">3 The BigInt Mode</h2>
<a name="Introduction-2"></a>
<h3 class="section">3.1 Introduction</h3>
<p>The bigint mode is enabled with the <code>&quot;use bigint&quot;</code> directive. It
propagates the same way as the strict mode. In bigint mode, all
integers are considered as <code>bigint</code> (arbitrarily large integer,
similar to the TC39 BigInt
proposal<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>)
instead of <code>number</code> (floating point number). In order to be able
to exchange data between standard and bigint modes, numbers are
internally represented as 3 different types:
</p>
<ul>
<li> Small integer (SmallInt): 32 bit integer<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>.
</li><li> Big integer (BigInt): arbitrarily large integer.
</li><li> Floating point number (Float).
</li></ul>
<p>In standard mode, the semantics of each operation is modified so that
when it returns a <code>number</code>, it is either of SmallInt or
Float. But the difference between SmallInt and Float is not observable
in standard mode.
</p>
<p>In bigint mode, each operation behaves differently whether its
operands are integer or float. The difference between SmallInt and
BigInt is not observable (i.e. they are both integers).
</p>
<p>The following table summarizes the observable types:
</p>
<table>
<thead><tr><th width="30%">Internal type</th><th width="30%">Observable type<br> (standard mode)</th><th width="30%">Observable type<br> (bigint mode)</th></tr></thead>
<tr><td width="30%">SmallInt</td><td width="30%">number</td><td width="30%">bigint</td></tr>
<tr><td width="30%">BigInt</td><td width="30%">bigint</td><td width="30%">bigint</td></tr>
<tr><td width="30%">Float</td><td width="30%">number</td><td width="30%">number</td></tr>
</table>
<a name="Changes-that-introduce-incompatibilities-with-Javascript"></a>
<h3 class="section">3.2 Changes that introduce incompatibilities with Javascript</h3>
<a name="Standard-mode"></a>
<h4 class="subsection">3.2.1 Standard mode</h4>
<p>There is no incompatibility with Javascript.
</p>
<a name="Bigint-mode"></a>
<h4 class="subsection">3.2.2 Bigint mode</h4>
<p>The following changes are visible:
</p>
<ul>
<li> Integer and Float are different types. Constants are typed. For example: <code>typeof 1.0 === &quot;number&quot;</code> and <code>typeof 1 === &quot;bigint&quot;</code>. Another consequence is that <code>1.0 === 1</code> is false.
</li><li> The range of integers is unlimited. In standard mode: <code>2**53 + 1 === 2**53</code>. This is no longer true with the bignum extensions.
</li><li> Binary bitwise operators do not truncate to 32 bits i.e. <code>0x800000000 | 1 === 0x800000001</code> while it gives <code>1</code> in standard mode.
</li><li> Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with <code>0x1f</code> i.e. <code>1 &lt;&lt; 32 === 4294967296</code> while it gives <code>1</code> in standard mode. However, the <code>&gt;&gt;&gt;</code> operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>.
</li><li> Operators with integer operands never return the minus zero floating point value as result. Hence <code>Object.is(0, -0) === true</code>. Use <code>-0.0</code> to create a minus zero floating point value.
</li><li> The <code>ToPrimitive</code> abstract operation is called with the <code>&quot;integer&quot;</code> preferred type when an integer is required (e.g. for bitwise binary or shift operations).
</li><li> The prototype of integers is no longer <code>Number.prototype</code>. Instead<br> <code>Object.getPrototypeOf(1) === BigInt.prototype</code>. The prototype of floats remains Number.prototype.
</li><li> If the TC39 BigInt proposal is supported, there is no observable difference between integers and <code>bigint</code>s.
</li></ul>
<a name="Operators"></a>
<h3 class="section">3.3 Operators</h3>
<a name="Arithmetic-operators"></a>
<h4 class="subsection">3.3.1 Arithmetic operators</h4>
<p>The operands are converted to number values as in normal
Javascript. Then the general case is that an Integer is returned if
both operands are Integer. Otherwise, a float is returned.
</p>
<p>The <code>+</code> operator also accepts strings as input and behaves like
standard Javascript in this case.
</p>
<p>The binary operator <code>%</code> returns the truncated remainder of the
division. When the result is an Integer type, a dividend of zero yields a
RangeError exception.
</p>
<p>The binary operator <code>%</code> in math mode returns the Euclidian
remainder of the division i.e. it is always positive.
</p>
<p>The binary operator <code>/</code> returns a float.
</p>
<p>The binary operator <code>/</code> in math mode returns a float if one of
the operands is float. Otherwise, <code>BigInt[Symbol.operatorDiv]</code> is
invoked.
</p>
<p>The returned type of <code>a ** b</code> is Float if <em>a</em> or <em>b</em>
are Float. If <em>a</em> and <em>b</em> are integers:
</p><ul>
<li> <em>b &lt; 0</em> returns a Float in bigint mode. In math mode, <code>BigInt[Symbol.operatorPow]</code> is invoked.
</li><li> <em>b &gt;= 0</em> returns an integer.
</li></ul>
<p>The unary <code>-</code> and unary <code>+</code> return the same type as their
operand. They performs no floating point rounding when the result is a
float.
</p>
<p>The unary operators <code>++</code> and <code>--</code> return the same type as
their operand.
</p>
<p>In standard mode:
</p>
<p>If the operator returns an Integer and that the result fits a
SmallInt, it is converted to SmallInt. Otherwise, the Integer is
converted to a Float.
</p>
<p>In bigint mode:
</p>
<p>If the operator returns an Integer and that the result fits a
SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
</p>
<a name="Logical-operators"></a>
<h4 class="subsection">3.3.2 Logical operators</h4>
<p>In standard mode:
</p>
<p>The operands have their standard behavior. If the result fits a
SmallInt it is converted to a SmallInt. Otherwise it is a Float.
</p>
<p>In bigint mode:
</p>
<p>The operands are converted to integer values. The floating point
values are converted to integer by rounding them to zero.
</p>
<p>The logical operators are defined assuming the integers are
represented in two complement notation.
</p>
<p>For <code>&lt;&lt;</code> and <code>&lt;&lt;</code>, the shift can be positive or negative. So
<code>a &lt;&lt; b</code> is defined as <em>\lfloor a/2^{-b} \rfloor</em> and
<code>a &gt;&gt; b</code> is defined as <em>\lfloor a/2^{b} \rfloor</em>.
</p>
<p>The operator <code>&gt;&gt;&gt;</code> is supported for backward compatibility and
behaves the same way as Javascript i.e. implicit conversion to <code>Uint32</code>.
</p>
<p>If the result fits a SmallInt it is converted to a SmallInt. Otherwise
it is a BigInt.
</p>
<a name="Relational-operators"></a>
<h4 class="subsection">3.3.3 Relational operators</h4>
<p>The relational operators &lt;, &lt;=, &gt;, &gt;=, ==, != work as expected with
integers and floating point numbers (e.g. <code>1.0 == 1</code> is true).
</p>
<p>The strict equality operators === and !== have the usual Javascript
semantics. In particular, different types never equal, so <code>1.0
=== 1</code> is false.
</p>
<a name="Number-literals"></a>
<h3 class="section">3.4 Number literals</h3>
<p>Number literals in bigint mode have a slightly different behavior than
in standard Javascript:
</p>
<ol>
<li> A number literal without a decimal point or an exponent is considered
as an Integer. Otherwise it is a Float.
</li><li> Hexadecimal, octal or binary floating point literals are accepted with
a decimal point or an exponent. The exponent is specified with the
<code>p</code> letter assuming a base 2. The same convention is used by
C99. Example: <code>0x1p3</code> is the same as <code>8.0</code>.
</li></ol>
<a name="Builtin-Object-changes-1"></a>
<h3 class="section">3.5 Builtin Object changes</h3>
<a name="BigInt-function"></a>
<h4 class="subsection">3.5.1 <code>BigInt</code> function</h4>
<p>The <code>BigInt</code> function cannot be invoked as a constructor. When
invoked as a function, it converts its first parameter to an
integer. When a floating point number is given as parameter, it is
truncated to an integer with infinite precision.
</p>
<p><code>BigInt</code> properties:
</p>
<dl compact="compact">
<dt><code>asIntN(bits, a)</code></dt>
<dd><p>Set <em>b=a \pmod{2^{bits}}</em>. Return <em>b</em> if <em>b &lt; 2^{bits-1}</em>
otherwise <em>b-2^{bits}</em>.
</p>
</dd>
<dt><code>asUintN(bits, a)</code></dt>
<dd><p>Return <em>a \pmod{2^{bits}}</em>.
</p>
</dd>
<dt><code>tdiv(a, b)</code></dt>
<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
exception.
@ -542,70 +187,10 @@ raised if <em>a &lt; 0</em>.
</dd>
</dl>
<a name="BigInt_002eprototype"></a>
<h4 class="subsection">3.5.2 <code>BigInt.prototype</code></h4>
<a name="BigFloat"></a>
<h2 class="chapter">4 BigFloat</h2>
<p>It is a normal object.
</p>
<a name="Number-constructor"></a>
<h4 class="subsection">3.5.3 <code>Number</code> constructor</h4>
<p>The number constructor returns its argument rounded to a Float using
the global floating point environment. In bigint mode, the Number
constructor returns a Float. In standard mode, it returns a SmallInt
if the value fits it, otherwise a Float.
</p>
<a name="Number_002eprototype"></a>
<h4 class="subsection">3.5.4 <code>Number.prototype</code></h4>
<p>The following properties are modified:
</p>
<dl compact="compact">
<dt><code>toString(radix)</code></dt>
<dd>
<p>In bigint mode, integers are converted to the specified radix with
infinite precision.
</p>
</dd>
<dt><code>toPrecision(p)</code></dt>
<dt><code>toFixed(p)</code></dt>
<dt><code>toExponential(p)</code></dt>
<dd>
<p>In bigint mode, integers are accepted and converted to string with
infinite precision.
</p>
</dd>
<dt><code>parseInt(string, radix)</code></dt>
<dd>
<p>In bigint mode, an integer is returned and the conversion is done with
infinite precision.
</p>
</dd>
</dl>
<a name="Math-object"></a>
<h4 class="subsection">3.5.5 <code>Math</code> object</h4>
<p>The following properties are modified:
</p>
<dl compact="compact">
<dt><code>abs(x)</code></dt>
<dd><p>Absolute value. Return an integer if <code>x</code> is an Integer. Otherwise
return a Float. No rounding is performed.
</p>
</dd>
<dt><code>min(a, b)</code></dt>
<dt><code>max(a, b)</code></dt>
<dd><p>No rounding is performed. The returned type is the same one as the
minimum (resp. maximum) value.
</p>
</dd>
</dl>
<a name="Arbitrarily-large-floating-point-numbers"></a>
<h2 class="chapter">4 Arbitrarily large floating point numbers</h2>
<a name="Introduction-3"></a>
<a name="Introduction-1"></a>
<h3 class="section">4.1 Introduction</h3>
<p>This extension adds the <code>BigFloat</code> primitive type. The
@ -628,8 +213,8 @@ environment are also set according to the result of the operation.
point environment is used.
</p>
<p>The rounding mode of the global floating point environment is always
<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF5" href="#FOOT5"><sup>5</sup></a>. The status flags of the global environment cannot be
read<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>. The precision of the global environment is
<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is
strictly smaller than the maximum allowed number of exponent bits
@ -646,7 +231,7 @@ when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
function can change the global floating point environment for its
callees but not for its caller.
</p>
<a name="Operators-1"></a>
<a name="Operators"></a>
<h3 class="section">4.3 Operators</h3>
<p>The builtin operators are extended so that a BigFloat is returned if
@ -669,9 +254,9 @@ equal when using the strict comparison operators (e.g. <code>0.0 ===
<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
suffix. BigFloat literals have an infinite precision. They are rounded
according to the global floating point environment when they are
evaluated.<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>
evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
</p>
<a name="Builtin-Object-changes-2"></a>
<a name="Builtin-Object-changes"></a>
<h3 class="section">4.5 Builtin Object changes</h3>
<a name="BigFloat-function"></a>
@ -739,6 +324,10 @@ point number <code>a</code> according to the floating point environment
<dd><p>Round to an integer. No additional rounding is performed.
</p>
</dd>
<dt><code>abs(x)</code></dt>
<dd><p>Return the absolute value of x. No additional rounding is performed.
</p>
</dd>
<dt><code>fmod(x, y[, e])</code></dt>
<dt><code>remainder(x, y[, e])</code></dt>
<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
@ -773,6 +362,10 @@ number. <code>e</code> is an optional floating point environment.
<p>The following properties are modified:
</p>
<dl compact="compact">
<dt><code>valueOf()</code></dt>
<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
</p>
</dd>
<dt><code>toString(radix)</code></dt>
<dd>
<p>For floating point numbers:
@ -787,14 +380,17 @@ the global precision and round to nearest gives the same number.
</li></ul>
<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
16 with a binary exponent and <code>@</code> for the other bases.
</p>
</dd>
<dt><code>toPrecision(p[, rnd_mode])</code></dt>
<dt><code>toFixed(p[, rnd_mode])</code></dt>
<dt><code>toExponential(p[, rnd_mode])</code></dt>
<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dd><p>Same semantics as the corresponding <code>Number</code> functions with
BigFloats. There is no limit on the accepted precision <code>p</code>. The
rounding mode can be optionally specified. It is set by default to
<code>BigFloatEnv.RNDNA</code>.
rounding mode and radix can be optionally specified. The radix must be
between 2 and 36.
</p>
</dd>
</dl>
@ -832,14 +428,14 @@ subnormal flags is set to <code>false</code>. If <code>rndMode</code> is
<dl compact="compact">
<dt><code>prec</code></dt>
<dd><p>Getter. Return the precision in bits of the global floating point
environment. The initial value is <code>53</code>.
environment. The initial value is <code>113</code>.
</p>
</dd>
<dt><code>expBits</code></dt>
<dd><p>Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. If <code>expBits &lt;
expBitsMax</code>, then subnormal numbers are supported. The initial value
is <code>11</code>.
is <code>15</code>.
</p>
</dd>
<dt><code>setPrec(f, p[, e])</code></dt>
@ -848,9 +444,7 @@ and the exponent size to <code>e</code> then call the function
<code>f</code>. Then the Float precision and exponent size are reset to
their precious value and the return value of <code>f</code> is returned (or
an exception is raised if <code>f</code> raised an exception). If <code>e</code>
is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>. <code>p</code>
must be &gt;= 53 and <code>e</code> must be &gt;= 11 so that the global precision
is at least equivalent to the IEEE 754 64 bit doubles.
is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
</p>
</dd>
<dt><code>precMin</code></dt>
@ -858,7 +452,7 @@ is at least equivalent to the IEEE 754 64 bit doubles.
</p>
</dd>
<dt><code>precMax</code></dt>
<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 53.
<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
</p>
</dd>
<dt><code>expBitsMin</code></dt>
@ -868,7 +462,7 @@ bits. Must be at least 3.
</dd>
<dt><code>expBitsMax</code></dt>
<dd><p>Read-only integer. Return the maximum allowed exponent size in
bits. Must be at least 11.
bits. Must be at least 15.
</p>
</dd>
<dt><code>RNDN</code></dt>
@ -891,11 +485,11 @@ bits. Must be at least 11.
<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
</p>
</dd>
<dt><code>RNDNU</code></dt>
<dd><p>Read-only integer. Round to nearest, with ties to +Infinity rounding mode.
<dt><code>RNDA</code></dt>
<dd><p>Read-only integer. Round away from zero rounding mode.
</p>
</dd>
<dt><code>RNDF<a name="DOCF8" href="#FOOT8"><sup>8</sup></a></code></dt>
<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
<dd><p>Read-only integer. Faithful rounding mode. The result is
non-deterministically rounded to -Infinity or +Infinity. This rounding
mode usually gives a faster and deterministic running time for the
@ -939,102 +533,200 @@ assuming an IEEE 754 representation.
</dd>
</dl>
<a name="Math-object-1"></a>
<h4 class="subsection">4.5.4 <code>Math</code> object</h4>
<a name="BigDecimal"></a>
<h2 class="chapter">5 BigDecimal</h2>
<p>The following properties are modified:
<p>This extension adds the <code>BigDecimal</code> primitive type. The
<code>BigDecimal</code> type represents floating point numbers in base
10. It is inspired from the proposal available at
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
</p>
<p>The <code>BigDecimal</code> floating point numbers are always normalized and
finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
<code>NaN</code>. By default, all the computations are done with infinite
precision.
</p>
<a name="Operators-1"></a>
<h3 class="section">5.1 Operators</h3>
<p>The following builtin operators support BigDecimal:
</p>
<dl compact="compact">
<dt><code>abs(x)</code></dt>
<dd><p>Absolute value. If <code>x</code> is a BigFloat, its absolute value is
returned as a BigFloat. No rounding is performed.
<dt><code>+</code></dt>
<dt><code>-</code></dt>
<dt><code>*</code></dt>
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
precision.
</p></dd>
<dt><code>%</code></dt>
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
precision. A range error is throws in case of division by zero.
</p>
</dd>
<dt><code>min(a, b)</code></dt>
<dt><code>max(a, b)</code></dt>
<dd><p>The returned type is the same one as the minimum (resp. maximum)
value, so <code>BigFloat</code> values are accepted. When a <code>BigFloat</code>
is returned, no rounding is performed.
<dt><code>/</code></dt>
<dd><p>Both operands must be BigDecimal. A range error is throws in case of
division by zero or if the result cannot be represented with infinite
precision (use <code>BigDecimal.div</code> to specify the rounding).
</p>
</dd>
<dt><code>**</code></dt>
<dd><p>Both operands must be BigDecimal. The exponent must be a positive
integer. The result is computed with infinite precision.
</p>
</dd>
<dt><code>===</code></dt>
<dd><p>When one of the operand is a BigDecimal, return true if both operands
are a BigDecimal and if they are equal.
</p>
</dd>
<dt><code>==</code></dt>
<dt><code>!=</code></dt>
<dt><code>&lt;=</code></dt>
<dt><code>&gt;=</code></dt>
<dt><code>&lt;</code></dt>
<dt><code>&gt;</code></dt>
<dd>
<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
converted to BigDecimal by using ToString(). Hence comparisons between
Number and BigDecimal do not use the exact mathematical value of the
Number value.
</p>
</dd>
</dl>
<a name="BigDecimal-literals"></a>
<h3 class="section">5.2 BigDecimal literals</h3>
<p>BigDecimal literals are decimal floating point numbers with a trailing
<code>m</code> suffix.
</p>
<a name="Builtin-Object-changes-1"></a>
<h3 class="section">5.3 Builtin Object changes</h3>
<a name="The-BigDecimal-function_002e"></a>
<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence
Number value are not converted to their exact numerical value as
BigDecimal.
</p>
<a name="Properties-of-the-BigDecimal-object"></a>
<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
<dl compact="compact">
<dt><code>add(a, b[, e])</code></dt>
<dt><code>sub(a, b[, e])</code></dt>
<dt><code>mul(a, b[, e])</code></dt>
<dt><code>div(a, b[, e])</code></dt>
<dt><code>mod(a, b[, e])</code></dt>
<dt><code>sqrt(a, e)</code></dt>
<dt><code>round(a, e)</code></dt>
<dd><p>Perform the specified floating point operation and round the floating
point result according to the rounding object <code>e</code>. If the
rounding object is not present, the operation is executed with
infinite precision.
</p>
<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
division by zero or if the result cannot be represented with infinite
precision if no rounding object is present.
</p>
<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
zero.
</p>
<p>The rounding object must contain the following properties:
<code>roundingMode</code> is a string specifying the rounding mode
(<code>&quot;floor&quot;</code>, <code>&quot;ceiling&quot;</code>, <code>&quot;down&quot;</code>, <code>&quot;up&quot;</code>,
<code>&quot;half-even&quot;</code>, <code>&quot;half-up&quot;</code>). Either
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
be present to specify respectively the number of significant digits
(must be &gt;= 1) or the number of digits after the decimal point (must
be &gt;= 0).
</p>
</dd>
</dl>
<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
<dl compact="compact">
<dt><code>valueOf()</code></dt>
<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
</p>
</dd>
<dt><code>toString()</code></dt>
<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
</p>
</dd>
<dt><code>toPrecision(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dt><code>toFixed(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dt><code>toExponential(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
precision <code>p</code>. There is no limit on the accepted precision
<code>p</code>. The rounding mode can be optionally
specified. <code>toPrecision</code> outputs either in decimal fixed notation
or in decimal exponential notation with a <code>p</code> digits of
precision. <code>toExponential</code> outputs in decimal exponential
notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
outputs in decimal notation with <code>p</code> digits after the decimal
point.
</p>
</dd>
</dl>
<a name="Math-mode"></a>
<h2 class="chapter">5 Math mode</h2>
<a name="Introduction-4"></a>
<h3 class="section">5.1 Introduction</h3>
<h2 class="chapter">6 Math mode</h2>
<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
directive. <code>&quot;use bigint&quot;</code> is implied in math mode. With this
mode, writing mathematical expressions is more intuitive, exact
results (e.g. fractions) can be computed for all operators and floating
point literals have the <code>BigFloat</code> type by default.
directive. It propagates the same way as the <em>strict mode</em>. It is
designed so that arbitrarily large integers and floating point numbers
are available by default. In order to minimize the number of changes
in the Javascript semantics, integers are represented either as Number
or BigInt depending on their magnitude. Floating point numbers are
always represented as BigFloat.
</p>
<p>It propagates the same way as the <em>strict mode</em>. In
this mode:
<p>The following changes are made to the Javascript semantics:
</p>
<ul>
<li> The <code>^</code> operator is a similar to the power operator (<code>**</code>).
<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === &quot;bigfloat&quot;</code>.
</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === &quot;number &quot;</code>, <code>typeof 1n === &quot;number&quot;</code> but <code>typeof 9007199254740992 === &quot;bigint&quot; </code>.
</li><li> All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
</li><li> The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
</li><li> The logical xor operator is still available with the <code>^^</code> operator.
</li><li> The division operator invokes <code>BigInt[Symbol.operatorDiv]</code> in case both operands are integers.
</li><li> The integer division operator can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
</li><li> The power operator invokes <code>BigInt[Symbol.operatorPow]</code> in case both operands are integers and the exponent is strictly negative.
</li><li> The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
</li><li> The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
</li><li> Floating point literals are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied).
</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
</li></ul>
<a name="Builtin-Object-changes-3"></a>
<h3 class="section">5.2 Builtin Object changes</h3>
<a name="Symbol-constructor-1"></a>
<h4 class="subsection">5.2.1 <code>Symbol</code> constructor</h4>
<p>The following global symbol is added for the operator overloading:
</p><dl compact="compact">
<dt><code>operatorMathMod</code></dt>
</dl>
<a name="Remaining-issues"></a>
<h3 class="section">5.3 Remaining issues</h3>
<ol>
<li> A new floating point literal suffix could be added for <code>Number</code> literals.
</li></ol>
<div class="footnote">
<hr>
<h4 class="footnotes-heading">Footnotes</h4>
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
<p>Could be extended to 53 bits without changing the principle.</p>
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
<p>The unsigned right right operator could be removed in bigint mode.</p>
<h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
<p>The
rationale is that the rounding mode changes must always be
explicit.</p>
<h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
<p>The rationale is to avoid side effects for the built-in
operators.</p>
<h3><a name="FOOT7" href="#DOCF7">(7)</a></h3>
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
<p>Base 10 floating point literals cannot usually be
exactly represented as base 2 floating point number. In order to
ensure that the literal is represented accurately with the current
precision, it must be evaluated at runtime.</p>
<h3><a name="FOOT8" href="#DOCF8">(8)</a></h3>
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
</div>
<hr>

Binary file not shown.

View File

@ -10,12 +10,12 @@
@sp 7
@center @titlefont{Javascript Bignum Extensions}
@sp 3
@center Version 2018-06-16
@center Version 2020-01-11
@sp 3
@center Author: Fabrice Bellard
@end titlepage
@setfilename spec.info
@setfilename jsbignum.info
@settitle Javascript Bignum Extensions
@contents
@ -27,347 +27,51 @@ language while being 100% backward compatible:
@itemize
@item Overloading of the standard operators
to support new types such as complex numbers, fractions or matrices.
@item Bigint mode where arbitrarily large integers are available by default (no @code{n} suffix is necessary as in the TC39 BigInt proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}}).
@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
@item Optional @code{math} mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
@url{https://github.com/littledan/proposal-bigdecimal}.
@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
remainder. @code{^} is an alias to the power operator
(@code{**}). @code{^^} is used as the exclusive or operator.
@end itemize
The extensions are independent from each other except the @code{math}
mode which relies on the bigint mode and the operator overloading.
mode which relies on BigFloat and operator overloading.
@chapter Operator overloading
@section Introduction
Operator overloading is inspired from the proposal available at
@url{https://github.com/tc39/proposal-operator-overloading/}. It
implements the same dispatch logic but finds the operator sets by
looking at the @code{Symbol.operatorSet} property in the objects. The
changes were done in order to simplify the implementation.
If the operands of an operator have at least one object type, a custom
operator method is searched before doing the legacy Javascript
@code{ToNumber} conversion.
For unary operators, the custom function is looked up in the object
and has the following name:
@table @code
@item unary +
@code{Symbol.operatorPlus}
@item unary -
@code{Symbol.operatorNeg}
@item ++
@code{Symbol.operatorInc}
@item --
@code{Symbol.operatorDec}
@item ~
@code{Symbol.operatorNot}
@end table
For binary operators:
More precisely, the following modifications were made:
@itemize
@item
If both operands have the same constructor function, then the operator
is looked up in the constructor.
@item @code{with operators from} is not supported. Operator overloading is always enabled.
@item
Otherwise, the property @code{Symbol.operatorOrder} is looked up in both
constructors and converted to @code{Int32}. The operator is then
looked in the constructor with the larger @code{Symbol.operatorOrder}
value. A @code{TypeError} is raised if both constructors have the same
@code{Symbol.operatorOrder} value.
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup the of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
@item @code{[]} cannot be overloaded.
@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@end itemize
The operator is looked up with the following name:
@chapter BigInt extensions
A few properties are added to the BigInt object:
@table @code
@item +
@code{Symbol.operatorAdd}
@item -
@code{Symbol.operatorSub}
@item *
@code{Symbol.operatorMul}
@item /
@code{Symbol.operatorDiv}
@item %
@code{Symbol.operatorMod}
@item % (math mode)
@code{Symbol.operatorMathMod}
@item **
@code{Symbol.operatorPow}
@item |
@code{Symbol.operatorOr}
@item ^
@code{Symbol.operatorXor}
@item &
@code{Symbol.operatorAnd}
@item <<
@code{Symbol.operatorShl}
@item >>
@code{Symbol.operatorShr}
@item <
@code{Symbol.operatorCmpLT}
@item >
@code{Symbol.operatorCmpLT}, operands swapped
@item <=
@code{Symbol.operatorCmpLE}
@item >=
@code{Symbol.operatorCmpLE}, operands swapped
@item ==, !=
@code{Symbol.operatorCmpEQ}
@end table
The return value of @code{Symbol.operatorCmpLT}, @code{Symbol.operatorCmpLE} and
@code{Symbol.operatorCmpEQ} is converted to @code{Boolean}.
@section Builtin Object changes
@subsection @code{Symbol} constructor
The following global symbols are added for the operator overloading:
@table @code
@item operatorOrder
@item operatorAdd
@item operatorSub
@item operatorMul
@item operatorDiv
@item operatorMod
@item operatorPow
@item operatorShl
@item operatorShr
@item operatorAnd
@item operatorOr
@item operatorXor
@item operatorCmpLT
@item operatorCmpLE
@item operatorCmpEQ
@item operatorPlus
@item operatorNeg
@item operatorNot
@item operatorInc
@item operatorDec
@end table
@chapter The BigInt Mode
@section Introduction
The bigint mode is enabled with the @code{"use bigint"} directive. It
propagates the same way as the strict mode. In bigint mode, all
integers are considered as @code{bigint} (arbitrarily large integer,
similar to the TC39 BigInt
proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}})
instead of @code{number} (floating point number). In order to be able
to exchange data between standard and bigint modes, numbers are
internally represented as 3 different types:
@itemize
@item Small integer (SmallInt): 32 bit integer@footnote{Could be extended to 53 bits without changing the principle.}.
@item Big integer (BigInt): arbitrarily large integer.
@item Floating point number (Float).
@end itemize
In standard mode, the semantics of each operation is modified so that
when it returns a @code{number}, it is either of SmallInt or
Float. But the difference between SmallInt and Float is not observable
in standard mode.
In bigint mode, each operation behaves differently whether its
operands are integer or float. The difference between SmallInt and
BigInt is not observable (i.e. they are both integers).
The following table summarizes the observable types:
@multitable @columnfractions .3 .3 .3
@headitem Internal type @tab Observable type@* (standard mode) @tab Observable type@* (bigint mode)
@item SmallInt @tab number @tab bigint
@item BigInt @tab bigint @tab bigint
@item Float @tab number @tab number
@end multitable
@section Changes that introduce incompatibilities with Javascript
@subsection Standard mode
There is no incompatibility with Javascript.
@subsection Bigint mode
The following changes are visible:
@itemize
@item Integer and Float are different types. Constants are typed. For example: @code{typeof 1.0 === "number"} and @code{typeof 1 === "bigint"}. Another consequence is that @code{1.0 === 1} is false.
@item The range of integers is unlimited. In standard mode: @code{2**53 + 1 === 2**53}. This is no longer true with the bignum extensions.
@item Binary bitwise operators do not truncate to 32 bits i.e. @code{0x800000000 | 1 === 0x800000001} while it gives @code{1} in standard mode.
@item Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with @code{0x1f} i.e. @code{1 << 32 === 4294967296} while it gives @code{1} in standard mode. However, the @code{>>>} operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior@footnote{The unsigned right right operator could be removed in bigint mode.}.
@item Operators with integer operands never return the minus zero floating point value as result. Hence @code{Object.is(0, -0) === true}. Use @code{-0.0} to create a minus zero floating point value.
@item The @code{ToPrimitive} abstract operation is called with the @code{"integer"} preferred type when an integer is required (e.g. for bitwise binary or shift operations).
@item The prototype of integers is no longer @code{Number.prototype}. Instead@* @code{Object.getPrototypeOf(1) === BigInt.prototype}. The prototype of floats remains Number.prototype.
@item If the TC39 BigInt proposal is supported, there is no observable difference between integers and @code{bigint}s.
@end itemize
@section Operators
@subsection Arithmetic operators
The operands are converted to number values as in normal
Javascript. Then the general case is that an Integer is returned if
both operands are Integer. Otherwise, a float is returned.
The @code{+} operator also accepts strings as input and behaves like
standard Javascript in this case.
The binary operator @code{%} returns the truncated remainder of the
division. When the result is an Integer type, a dividend of zero yields a
RangeError exception.
The binary operator @code{%} in math mode returns the Euclidian
remainder of the division i.e. it is always positive.
The binary operator @code{/} returns a float.
The binary operator @code{/} in math mode returns a float if one of
the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is
invoked.
The returned type of @code{a ** b} is Float if @math{a} or @math{b}
are Float. If @math{a} and @math{b} are integers:
@itemize
@item @math{b < 0} returns a Float in bigint mode. In math mode, @code{BigInt[Symbol.operatorPow]} is invoked.
@item @math{b >= 0} returns an integer.
@end itemize
The unary @code{-} and unary @code{+} return the same type as their
operand. They performs no floating point rounding when the result is a
float.
The unary operators @code{++} and @code{--} return the same type as
their operand.
In standard mode:
If the operator returns an Integer and that the result fits a
SmallInt, it is converted to SmallInt. Otherwise, the Integer is
converted to a Float.
In bigint mode:
If the operator returns an Integer and that the result fits a
SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
@subsection Logical operators
In standard mode:
The operands have their standard behavior. If the result fits a
SmallInt it is converted to a SmallInt. Otherwise it is a Float.
In bigint mode:
The operands are converted to integer values. The floating point
values are converted to integer by rounding them to zero.
The logical operators are defined assuming the integers are
represented in two complement notation.
For @code{<<} and @code{<<}, the shift can be positive or negative. So
@code{a << b} is defined as @math{\lfloor a/2^{-b} \rfloor} and
@code{a >> b} is defined as @math{\lfloor a/2^{b} \rfloor}.
The operator @code{>>>} is supported for backward compatibility and
behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}.
If the result fits a SmallInt it is converted to a SmallInt. Otherwise
it is a BigInt.
@subsection Relational operators
The relational operators <, <=, >, >=, ==, != work as expected with
integers and floating point numbers (e.g. @code{1.0 == 1} is true).
The strict equality operators === and !== have the usual Javascript
semantics. In particular, different types never equal, so @code{1.0
=== 1} is false.
@section Number literals
Number literals in bigint mode have a slightly different behavior than
in standard Javascript:
@enumerate
@item
A number literal without a decimal point or an exponent is considered
as an Integer. Otherwise it is a Float.
@item
Hexadecimal, octal or binary floating point literals are accepted with
a decimal point or an exponent. The exponent is specified with the
@code{p} letter assuming a base 2. The same convention is used by
C99. Example: @code{0x1p3} is the same as @code{8.0}.
@end enumerate
@section Builtin Object changes
@subsection @code{BigInt} function
The @code{BigInt} function cannot be invoked as a constructor. When
invoked as a function, it converts its first parameter to an
integer. When a floating point number is given as parameter, it is
truncated to an integer with infinite precision.
@code{BigInt} properties:
@table @code
@item asIntN(bits, a)
Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}}
otherwise @math{b-2^{bits}}.
@item asUintN(bits, a)
Return @math{a \pmod{2^{bits}}}.
@item tdiv(a, b)
Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
@ -410,58 +114,7 @@ Return the number of trailing zeros in the two's complement binary representatio
@end table
@subsection @code{BigInt.prototype}
It is a normal object.
@subsection @code{Number} constructor
The number constructor returns its argument rounded to a Float using
the global floating point environment. In bigint mode, the Number
constructor returns a Float. In standard mode, it returns a SmallInt
if the value fits it, otherwise a Float.
@subsection @code{Number.prototype}
The following properties are modified:
@table @code
@item toString(radix)
In bigint mode, integers are converted to the specified radix with
infinite precision.
@item toPrecision(p)
@item toFixed(p)
@item toExponential(p)
In bigint mode, integers are accepted and converted to string with
infinite precision.
@item parseInt(string, radix)
In bigint mode, an integer is returned and the conversion is done with
infinite precision.
@end table
@subsection @code{Math} object
The following properties are modified:
@table @code
@item abs(x)
Absolute value. Return an integer if @code{x} is an Integer. Otherwise
return a Float. No rounding is performed.
@item min(a, b)
@item max(a, b)
No rounding is performed. The returned type is the same one as the
minimum (resp. maximum) value.
@end table
@chapter Arbitrarily large floating point numbers
@chapter BigFloat
@section Introduction
@ -590,6 +243,9 @@ point number @code{a} according to the floating point environment
@item trunc(x)
Round to an integer. No additional rounding is performed.
@item abs(x)
Return the absolute value of x. No additional rounding is performed.
@item fmod(x, y[, e])
@item remainder(x, y[, e])
Floating point remainder. The quotient is truncated to zero (fmod) or
@ -620,6 +276,9 @@ number. @code{e} is an optional floating point environment.
The following properties are modified:
@table @code
@item valueOf()
Return the bigfloat primitive value corresponding to @code{this}.
@item toString(radix)
For floating point numbers:
@ -636,13 +295,16 @@ the global precision and round to nearest gives the same number.
@end itemize
@item toPrecision(p[, rnd_mode])
@item toFixed(p[, rnd_mode])
@item toExponential(p[, rnd_mode])
The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
16 with a binary exponent and @code{@@} for the other bases.
@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
Same semantics as the corresponding @code{Number} functions with
BigFloats. There is no limit on the accepted precision @code{p}. The
rounding mode can be optionally specified. It is set by default to
@code{BigFloatEnv.RNDNA}.
rounding mode and radix can be optionally specified. The radix must be
between 2 and 36.
@end table
@ -679,13 +341,13 @@ subnormal flags is set to @code{false}. If @code{rndMode} is
@item prec
Getter. Return the precision in bits of the global floating point
environment. The initial value is @code{53}.
environment. The initial value is @code{113}.
@item expBits
Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. If @code{expBits <
expBitsMax}, then subnormal numbers are supported. The initial value
is @code{11}.
is @code{15}.
@item setPrec(f, p[, e])
Set the precision of the global floating point environment to @code{p}
@ -693,15 +355,13 @@ and the exponent size to @code{e} then call the function
@code{f}. Then the Float precision and exponent size are reset to
their precious value and the return value of @code{f} is returned (or
an exception is raised if @code{f} raised an exception). If @code{e}
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. @code{p}
must be >= 53 and @code{e} must be >= 11 so that the global precision
is at least equivalent to the IEEE 754 64 bit doubles.
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
@item precMin
Read-only integer. Return the minimum allowed precision. Must be at least 2.
@item precMax
Read-only integer. Return the maximum allowed precision. Must be at least 53.
Read-only integer. Return the maximum allowed precision. Must be at least 113.
@item expBitsMin
Read-only integer. Return the minimum allowed exponent size in
@ -709,7 +369,7 @@ bits. Must be at least 3.
@item expBitsMax
Read-only integer. Return the maximum allowed exponent size in
bits. Must be at least 11.
bits. Must be at least 15.
@item RNDN
Read-only integer. Round to nearest, with ties to even rounding mode.
@ -726,8 +386,8 @@ Read-only integer. Round to +Infinity rounding mode.
@item RNDNA
Read-only integer. Round to nearest, with ties away from zero rounding mode.
@item RNDNU
Read-only integer. Round to nearest, with ties to +Infinity rounding mode.
@item RNDA
Read-only integer. Round away from zero rounding mode.
@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
Read-only integer. Faithful rounding mode. The result is
@ -767,69 +427,166 @@ Getter and setter (Boolean). Status flags.
@end table
@subsection @code{Math} object
@chapter BigDecimal
The following properties are modified:
This extension adds the @code{BigDecimal} primitive type. The
@code{BigDecimal} type represents floating point numbers in base
10. It is inspired from the proposal available at
@url{https://github.com/littledan/proposal-bigdecimal}.
The @code{BigDecimal} floating point numbers are always normalized and
finite. There is no concept of @code{-0}, @code{Infinity} or
@code{NaN}. By default, all the computations are done with infinite
precision.
@section Operators
The following builtin operators support BigDecimal:
@table @code
@item abs(x)
Absolute value. If @code{x} is a BigFloat, its absolute value is
returned as a BigFloat. No rounding is performed.
@item min(a, b)
@item max(a, b)
The returned type is the same one as the minimum (resp. maximum)
value, so @code{BigFloat} values are accepted. When a @code{BigFloat}
is returned, no rounding is performed.
@item +
@item -
@item *
Both operands must be BigDecimal. The result is computed with infinite
precision.
@item %
Both operands must be BigDecimal. The result is computed with infinite
precision. A range error is throws in case of division by zero.
@item /
Both operands must be BigDecimal. A range error is throws in case of
division by zero or if the result cannot be represented with infinite
precision (use @code{BigDecimal.div} to specify the rounding).
@item **
Both operands must be BigDecimal. The exponent must be a positive
integer. The result is computed with infinite precision.
@item ===
When one of the operand is a BigDecimal, return true if both operands
are a BigDecimal and if they are equal.
@item ==
@item !=
@item <=
@item >=
@item <
@item >
Numerical comparison. When one of the operand is not a BigDecimal, it is
converted to BigDecimal by using ToString(). Hence comparisons between
Number and BigDecimal do not use the exact mathematical value of the
Number value.
@end table
@section BigDecimal literals
BigDecimal literals are decimal floating point numbers with a trailing
@code{m} suffix.
@section Builtin Object changes
@subsection The @code{BigDecimal} function.
It returns @code{0m} if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence
Number value are not converted to their exact numerical value as
BigDecimal.
@subsection Properties of the @code{BigDecimal} object
@table @code
@item add(a, b[, e])
@item sub(a, b[, e])
@item mul(a, b[, e])
@item div(a, b[, e])
@item mod(a, b[, e])
@item sqrt(a, e)
@item round(a, e)
Perform the specified floating point operation and round the floating
point result according to the rounding object @code{e}. If the
rounding object is not present, the operation is executed with
infinite precision.
For @code{div}, a @code{RangeError} exception is thrown in case of
division by zero or if the result cannot be represented with infinite
precision if no rounding object is present.
For @code{sqrt}, a range error is thrown if @code{a} is less than
zero.
The rounding object must contain the following properties:
@code{roundingMode} is a string specifying the rounding mode
(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
@code{"half-even"}, @code{"half-up"}). Either
@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
be present to specify respectively the number of significant digits
(must be >= 1) or the number of digits after the decimal point (must
be >= 0).
@end table
@subsection Properties of the @code{BigDecimal.prototype} object
@table @code
@item valueOf()
Return the bigdecimal primitive value corresponding to @code{this}.
@item toString()
Convert @code{this} to a string with infinite precision in base 10.
@item toPrecision(p, rnd_mode = "half-up")
@item toFixed(p, rnd_mode = "half-up")
@item toExponential(p, rnd_mode = "half-up")
Convert the BigDecimal @code{this} to string with the specified
precision @code{p}. There is no limit on the accepted precision
@code{p}. The rounding mode can be optionally
specified. @code{toPrecision} outputs either in decimal fixed notation
or in decimal exponential notation with a @code{p} digits of
precision. @code{toExponential} outputs in decimal exponential
notation with @code{p} digits after the decimal point. @code{toFixed}
outputs in decimal notation with @code{p} digits after the decimal
point.
@end table
@chapter Math mode
@section Introduction
A new @emph{math mode} is enabled with the @code{"use math"}
directive. @code{"use bigint"} is implied in math mode. With this
mode, writing mathematical expressions is more intuitive, exact
results (e.g. fractions) can be computed for all operators and floating
point literals have the @code{BigFloat} type by default.
directive. It propagates the same way as the @emph{strict mode}. It is
designed so that arbitrarily large integers and floating point numbers
are available by default. In order to minimize the number of changes
in the Javascript semantics, integers are represented either as Number
or BigInt depending on their magnitude. Floating point numbers are
always represented as BigFloat.
It propagates the same way as the @emph{strict mode}. In
this mode:
The following changes are made to the Javascript semantics:
@itemize
@item The @code{^} operator is a similar to the power operator (@code{**}).
@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
@item The @code{^} operator is an alias to the power operator (@code{**}).
@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
@item The logical xor operator is still available with the @code{^^} operator.
@item The division operator invokes @code{BigInt[Symbol.operatorDiv]} in case both operands are integers.
@item The integer division operator can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
@item The power operator invokes @code{BigInt[Symbol.operatorPow]} in case both operands are integers and the exponent is strictly negative.
@item The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
@item The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
@item Floating point literals are @code{BigFloat} by default (i.e. a @code{l} suffix is implied).
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
@end itemize
@section Builtin Object changes
@subsection @code{Symbol} constructor
The following global symbol is added for the operator overloading:
@table @code
@item operatorMathMod
@end table
@section Remaining issues
@enumerate
@item A new floating point literal suffix could be added for @code{Number} literals.
@end enumerate
@bye

View File

@ -1,7 +1,8 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>QuickJS Javascript Engine</title>
<meta name="description" content="QuickJS Javascript Engine">
@ -9,7 +10,6 @@
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
@ -206,7 +206,7 @@ Javascript files and/or expressions as arguments to execute them:
<a name="qjs-interpreter"></a>
<h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>
<pre class="verbatim">usage: qjs [options] [files]
<pre class="verbatim">usage: qjs [options] [file [args]]
</pre>
<p>Options are:
</p><dl compact="compact">
@ -241,6 +241,11 @@ source is <code>import</code>.
the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.
</p>
</dd>
<dt><code>-I file</code></dt>
<dt><code>--include file</code></dt>
<dd><p>Include an additional file.
</p>
</dd>
</dl>
<p>Advanced options are:
@ -767,6 +772,10 @@ pathname of <code>path</code> and <code>err</code> the error code.
and <code>err</code> the error code.
</p>
</dd>
<dt><code>chdir(path)</code></dt>
<dd><p>Change the current directory. Return the error code.
</p>
</dd>
<dt><code>mkdir(path, mode = 0o777)</code></dt>
<dd><p>Create a directory at <code>path</code>. Return the error code.
</p>

Binary file not shown.

View File

@ -92,7 +92,7 @@ generates a @code{hello} executable with no external dependency.
@subsection @code{qjs} interpreter
@verbatim
usage: qjs [options] [files]
usage: qjs [options] [file [args]]
@end verbatim
Options are:
@ -122,6 +122,10 @@ Load as ES6 script (default=autodetect).
Enable the bignum extensions: BigDecimal object, BigFloat object and
the @code{"use bigint"} and @code{"use math"} directives.
@item -I file
@item --include file
Include an additional file.
@end table
Advanced options are:
@ -576,6 +580,9 @@ pathname of @code{path} and @code{err} the error code.
Return @code{[str, err]} where @code{str} is the current working directory
and @code{err} the error code.
@item chdir(path)
Change the current directory. Return the error code.
@item mkdir(path, mode = 0o777)
Create a directory at @code{path}. Return the error code.

View File

@ -6,10 +6,10 @@
/* compute PI with a precision of 'prec' digits */
function calc_pi(prec) {
const CHUD_A = 13591409d;
const CHUD_B = 545140134d;
const CHUD_C = 640320d;
const CHUD_C3 = 10939058860032000d; /* C^3/24 */
const CHUD_A = 13591409m;
const CHUD_B = 545140134m;
const CHUD_C = 640320m;
const CHUD_C3 = 10939058860032000m; /* C^3/24 */
const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
/* return [P, Q, G] */
@ -17,7 +17,7 @@ function calc_pi(prec) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
if (a == (b - 1n)) {
b1 = BigDecimal(b);
G = (2d * b1 - 1d) * (6d * b1 - 1d) * (6d * b1 - 5d);
G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
P = G * (CHUD_B * b1 + CHUD_A);
if (b & 1n)
P = -P;
@ -32,7 +32,7 @@ function calc_pi(prec) {
if (need_G)
G = G1 * G2;
else
G = 0d;
G = 0m;
}
return [P, Q, G];
}
@ -44,7 +44,7 @@ function calc_pi(prec) {
Q = BigDecimal.div(Q, (P + Q * CHUD_A),
{ roundingMode: "half-even",
maximumSignificantDigits: prec });
G = (CHUD_C / 12d) * BigDecimal.sqrt(CHUD_C,
G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
{ roundingMode: "half-even",
maximumSignificantDigits: prec });
return Q * G;
@ -64,7 +64,5 @@ function calc_pi(prec) {
/* we add more digits to reduce the probability of bad rounding for
the last digits */
r = calc_pi(n_digits + 20);
r = BigDecimal.round(r, { roundingMode: "down",
maximumFractionDigits: n_digits })
print(r);
print(r.toFixed(n_digits, "down"));
})();

1126
libbf.c

File diff suppressed because it is too large Load Diff

119
libbf.h
View File

@ -41,8 +41,8 @@ typedef unsigned __int128 uint128_t;
typedef int64_t slimb_t;
typedef uint64_t limb_t;
typedef uint128_t dlimb_t;
#define EXP_MIN INT64_MIN
#define EXP_MAX INT64_MAX
#define BF_RAW_EXP_MIN INT64_MIN
#define BF_RAW_EXP_MAX INT64_MAX
#define LIMB_DIGITS 19
#define BF_DEC_BASE UINT64_C(10000000000000000000)
@ -52,8 +52,8 @@ typedef uint128_t dlimb_t;
typedef int32_t slimb_t;
typedef uint32_t limb_t;
typedef uint64_t dlimb_t;
#define EXP_MIN INT32_MIN
#define EXP_MAX INT32_MAX
#define BF_RAW_EXP_MIN INT32_MIN
#define BF_RAW_EXP_MAX INT32_MAX
#define LIMB_DIGITS 9
#define BF_DEC_BASE 1000000000U
@ -61,10 +61,17 @@ typedef uint64_t dlimb_t;
#endif
/* in bits */
/* minimum number of bits for the exponent */
#define BF_EXP_BITS_MIN 3
#define BF_EXP_BITS_MAX (LIMB_BITS - 2)
/* maximum number of bits for the exponent */
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
/* extended range for exponent, used internally */
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
/* minimum possible precision */
#define BF_PREC_MIN 2
#define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2)
/* minimum possible precision */
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
/* some operations support infinite precision */
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
#if LIMB_BITS == 64
@ -73,9 +80,9 @@ typedef uint64_t dlimb_t;
#define BF_CHKSUM_MOD 975620677U
#endif
#define BF_EXP_ZERO EXP_MIN
#define BF_EXP_INF (EXP_MAX - 1)
#define BF_EXP_NAN EXP_MAX
#define BF_EXP_ZERO BF_RAW_EXP_MIN
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
#define BF_EXP_NAN BF_RAW_EXP_MAX
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
@ -101,27 +108,29 @@ typedef struct {
typedef enum {
BF_RNDN, /* round to nearest, ties to even */
BF_RNDZ, /* round to zero */
BF_RNDD, /* round to -inf */
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
BF_RNDU, /* round to +inf */
BF_RNDNA, /* round to nearest, ties away from zero */
BF_RNDNU, /* round to nearest, ties to +inf */
BF_RNDA, /* round away from zero */
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
inexact flag is always set) */
} bf_rnd_t;
/* allow subnormal numbers. Only available if the number of exponent
bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF. Not supported
for decimal floating point numbers. */
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
#define BF_FLAG_SUBNORMAL (1 << 3)
/* 'prec' is the precision after the radix point instead of the whole
mantissa. Can only be used with bf_round(), bfdec_round() and
bfdev_div(). */
mantissa. Can only be used with bf_round() and
bfdec_[add|sub|mul|div|sqrt|round](). */
#define BF_FLAG_RADPNT_PREC (1 << 4)
#define BF_RND_MASK 0x7
#define BF_EXP_BITS_SHIFT 5
#define BF_EXP_BITS_MASK 0x3f
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
/* contains the rounding mode and number of exponents bits */
typedef uint32_t bf_flags_t;
@ -142,12 +151,17 @@ typedef struct bf_context_t {
static inline int bf_get_exp_bits(bf_flags_t flags)
{
return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK);
int e;
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
if (e == BF_EXP_BITS_MASK)
return BF_EXP_BITS_MAX + 1;
else
return BF_EXP_BITS_MAX - e;
}
static inline bf_flags_t bf_set_exp_bits(int n)
{
return (BF_EXP_BITS_MAX - n) << BF_EXP_BITS_SHIFT;
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
}
/* returned status */
@ -249,9 +263,22 @@ int bf_set_float64(bf_t *a, double d);
int bf_cmpu(const bf_t *a, const bf_t *b);
int bf_cmp_full(const bf_t *a, const bf_t *b);
int bf_cmp_eq(const bf_t *a, const bf_t *b);
int bf_cmp_le(const bf_t *a, const bf_t *b);
int bf_cmp_lt(const bf_t *a, const bf_t *b);
int bf_cmp(const bf_t *a, const bf_t *b);
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) == 0;
}
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) <= 0;
}
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) < 0;
}
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
@ -264,12 +291,10 @@ int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags)
#define BF_DIVREM_EUCLIDIAN BF_RNDF
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
limb_t prec, bf_flags_t flags, int rnd_mode);
int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags);
int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags);
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags, int rnd_mode);
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags);
bf_flags_t flags, int rnd_mode);
/* round to integer with infinite precision */
int bf_rint(bf_t *r, int rnd_mode);
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
@ -304,8 +329,8 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
/* Conversion of floating point number to string. Return a null
terminated string or NULL if memory error. *plen contains its
length if plen != NULL. The exponent letter is "e" for base 10,
"p" for bases 2, 8, 16 with the binary exponent and "@" for the
other bases. */
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
bases. */
#define BF_FTOA_FORMAT_MASK (3 << 16)
@ -316,17 +341,23 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
/* fractional format: prec digits after the decimal point rounded with
(flags & BF_RND_MASK) */
#define BF_FTOA_FORMAT_FRAC (1 << 16)
/* free format: use as many digits as necessary so that bf_atof()
return the same number when using precision 'prec', rounding to
nearest and the subnormal+exponent configuration of 'flags'. The
result is meaningful only if 'a' is already rounded to the wanted
precision.
/* free format:
Infinite precision (BF_PREC_INF) is supported when the radix is a
power of two. */
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
number of digits to represent 'a'. The precision and the rounding
mode are ignored.
For the non binary radices with bf_ftoa(): use as many digits as
necessary so that bf_atof() return the same number when using
precision 'prec', rounding to nearest and the subnormal
configuration of 'flags'. The result is meaningful only if 'a' is
already rounded to 'prec' bits. If the subnormal flag is set, the
exponent in 'flags' must also be set to the desired exponent range.
*/
#define BF_FTOA_FORMAT_FREE (2 << 16)
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
(takes more computation time). */
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
binary radices with bf_ftoa() and for bfdec_ftoa(). */
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
/* force exponential notation for fixed or free format */
@ -370,7 +401,7 @@ int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
#define BF_POW_JS_QUICKS (1 << 16)
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
@ -448,17 +479,21 @@ static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
}
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp((const bf_t *)a, (const bf_t *)b);
}
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp_eq((const bf_t *)a, (const bf_t *)b);
return bfdec_cmp(a, b) == 0;
}
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp_le((const bf_t *)a, (const bf_t *)b);
return bfdec_cmp(a, b) <= 0;
}
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp_lt((const bf_t *)a, (const bf_t *)b);
return bfdec_cmp(a, b) < 0;
}
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
@ -475,8 +510,8 @@ int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
limb_t prec, bf_flags_t flags, int rnd_mode);
int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags, int rnd_mode);
int bfdec_rint(bfdec_t *r, int rnd_mode);
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
@ -488,7 +523,7 @@ int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
limb_t prec, bf_flags_t flags);
/* the following functions are exported for testing only. */
extern limb_t mp_pow_dec[LIMB_DIGITS + 1];
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
void bfdec_print_str(const char *str, const bfdec_t *a);
static inline int bfdec_resize(bfdec_t *r, limb_t len)
{

26
qjs.c
View File

@ -41,9 +41,6 @@
#include "cutils.h"
#include "quickjs-libc.h"
/* enable bignums */
#define CONFIG_BIGNUM
extern const uint8_t qjsc_repl[];
extern const uint32_t qjsc_repl_size;
#ifdef CONFIG_BIGNUM
@ -258,12 +255,13 @@ static const JSMallocFunctions trace_mf = {
void help(void)
{
printf("QuickJS version " CONFIG_VERSION "\n"
"usage: " PROG_NAME " [options] [file]\n"
"usage: " PROG_NAME " [options] [file [args]]\n"
"-h --help list options\n"
"-e --eval EXPR evaluate EXPR\n"
"-i --interactive go to interactive mode\n"
"-m --module load as ES6 module (default=autodetect)\n"
" --script load as ES6 script (default=autodetect)\n"
"-I --include file include an additional file\n"
" --std make 'std' and 'os' available to the loaded script\n"
#ifdef CONFIG_BIGNUM
" --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
@ -292,6 +290,8 @@ int main(int argc, char **argv)
int load_std = 0;
int dump_unhandled_promise_rejection = 0;
size_t memory_limit = 0;
char *include_list[32];
int i, include_count = 0;
#ifdef CONFIG_BIGNUM
int load_jscalc, bignum_ext = 0;
#endif
@ -345,6 +345,18 @@ int main(int argc, char **argv)
fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
}
if (opt == 'I' || !strcmp(longopt, "include")) {
if (optind >= argc) {
fprintf(stderr, "expecting filename");
exit(1);
}
if (include_count >= countof(include_list)) {
fprintf(stderr, "too many included files");
exit(1);
}
include_list[include_count++] = argv[optind++];
continue;
}
if (opt == 'i' || !strcmp(longopt, "interactive")) {
interactive++;
continue;
@ -426,6 +438,7 @@ int main(int argc, char **argv)
if (bignum_ext || load_jscalc) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
@ -459,6 +472,11 @@ int main(int argc, char **argv)
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
}
for(i = 0; i < include_count; i++) {
if (eval_file(ctx, include_list[i], module))
goto fail;
}
if (expr) {
if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))
goto fail;

24
qjsc.c
View File

@ -36,9 +36,6 @@
#include "cutils.h"
#include "quickjs-libc.h"
/* enable bignums */
#define CONFIG_BIGNUM
typedef struct {
char *name;
char *short_name;
@ -79,7 +76,9 @@ static const FeatureEntry feature_list[] = {
{ "promise", "Promise" },
#define FE_MODULE_LOADER 9
{ "module-loader", NULL },
#ifdef CONFIG_BIGNUM
{ "bigint", "BigInt" },
#endif
};
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
@ -485,9 +484,12 @@ int main(int argc, char **argv)
FILE *fo;
JSRuntime *rt;
JSContext *ctx;
BOOL use_lto, bignum_ext;
BOOL use_lto;
int module;
OutputTypeEnum output_type;
#ifdef CONFIG_BIGNUM
BOOL bignum_ext = FALSE;
#endif
out_filename = NULL;
output_type = OUTPUT_EXECUTABLE;
@ -497,7 +499,6 @@ int main(int argc, char **argv)
byte_swap = FALSE;
verbose = 0;
use_lto = FALSE;
bignum_ext = FALSE;
/* add system modules */
namelist_add(&cmodule_list, "std", "std", 0);
@ -538,9 +539,13 @@ int main(int argc, char **argv)
}
if (i == countof(feature_list))
goto bad_feature;
} else if (!strcmp(optarg, "bignum")) {
} else
#ifdef CONFIG_BIGNUM
if (!strcmp(optarg, "bignum")) {
bignum_ext = TRUE;
} else {
} else
#endif
{
bad_feature:
fprintf(stderr, "unsupported feature: %s\n", optarg);
exit(1);
@ -615,6 +620,7 @@ int main(int argc, char **argv)
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
@ -661,13 +667,15 @@ int main(int argc, char **argv)
feature_list[i].init_name);
}
}
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
fprintf(fo,
" JS_AddIntrinsicBigFloat(ctx);\n"
" JS_AddIntrinsicBigDecimal(ctx);\n"
" JS_AddIntrinsicOperators(ctx);\n"
" JS_EnableBignumExt(ctx, 1);\n");
}
#endif
fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
for(i = 0; i < init_module_list.count; i++) {

1437
qjscalc.js

File diff suppressed because it is too large Load Diff

View File

@ -219,6 +219,8 @@ DEF(BigInt, "BigInt")
DEF(BigFloat, "BigFloat")
DEF(BigFloatEnv, "BigFloatEnv")
DEF(BigDecimal, "BigDecimal")
DEF(OperatorSet, "OperatorSet")
DEF(Operators, "Operators")
#endif
DEF(Map, "Map")
DEF(Set, "Set") /* Map + 1 */
@ -263,27 +265,7 @@ DEF(Symbol_species, "Symbol.species")
DEF(Symbol_unscopables, "Symbol.unscopables")
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
#ifdef CONFIG_BIGNUM
DEF(Symbol_operatorOrder, "Symbol.operatorOrder")
DEF(Symbol_operatorAdd, "Symbol.operatorAdd")
DEF(Symbol_operatorSub, "Symbol.operatorSub")
DEF(Symbol_operatorMul, "Symbol.operatorMul")
DEF(Symbol_operatorDiv, "Symbol.operatorDiv")
DEF(Symbol_operatorMod, "Symbol.operatorMod")
DEF(Symbol_operatorPow, "Symbol.operatorPow")
DEF(Symbol_operatorShl, "Symbol.operatorShl")
DEF(Symbol_operatorShr, "Symbol.operatorShr")
DEF(Symbol_operatorAnd, "Symbol.operatorAnd")
DEF(Symbol_operatorOr, "Symbol.operatorOr")
DEF(Symbol_operatorXor, "Symbol.operatorXor")
DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT")
DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE")
DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ")
DEF(Symbol_operatorPlus, "Symbol.operatorPlus")
DEF(Symbol_operatorNeg, "Symbol.operatorNeg")
DEF(Symbol_operatorNot, "Symbol.operatorNot")
DEF(Symbol_operatorInc, "Symbol.operatorInc")
DEF(Symbol_operatorDec, "Symbol.operatorDec")
DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod")
DEF(Symbol_operatorSet, "Symbol.operatorSet")
#endif
#endif /* DEF */

View File

@ -2027,6 +2027,20 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
#if !defined(_WIN32)
static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
const char *target;
int err;
target = JS_ToCString(ctx, argv[0]);
if (!target)
return JS_EXCEPTION;
err = chdir(target);
JS_FreeCString(ctx, target);
return js_os_return(ctx, err);
}
/* return [path, errorcode] */
static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@ -2581,6 +2595,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
#if !defined(_WIN32)
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),

View File

@ -260,9 +260,7 @@ DEF( or, 1, 2, 1, none)
DEF(is_undefined_or_null, 1, 1, 1, none)
#ifdef CONFIG_BIGNUM
DEF( mul_pow10, 1, 2, 1, none)
DEF( math_div, 1, 2, 1, none)
DEF( math_mod, 1, 2, 1, none)
DEF( math_pow, 1, 2, 1, none)
#endif
/* must be the last non short and non temporary opcode */
DEF( nop, 1, 0, 0, none)
@ -271,7 +269,6 @@ DEF( nop, 1, 0, 0, none)
def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */

3206
quickjs.c

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@ typedef struct JSClass JSClass;
typedef uint32_t JSClassID;
typedef uint32_t JSAtom;
#if defined(__x86_64__) || defined(__aarch64__)
#if INTPTR_MAX >= INT64_MAX
#define JS_PTR64
#define JS_PTR64_DEF(a) a
#else
@ -366,7 +366,9 @@ void JS_AddIntrinsicPromise(JSContext *ctx);
void JS_AddIntrinsicBigInt(JSContext *ctx);
void JS_AddIntrinsicBigFloat(JSContext *ctx);
void JS_AddIntrinsicBigDecimal(JSContext *ctx);
/* enable "use bigint", "use math" and operator overloading */
/* enable operator overloading */
void JS_AddIntrinsicOperators(JSContext *ctx);
/* enable "use math" */
void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
@ -531,12 +533,16 @@ static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
return v;
}
JS_BOOL JS_IsNumber(JSValueConst v);
static inline JS_BOOL JS_IsInteger(JSValueConst v)
static inline JS_BOOL JS_IsNumber(JSValueConst v)
{
int tag = JS_VALUE_GET_TAG(v);
return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT;
return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
}
static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
{
int tag = JS_VALUE_GET_TAG(v);
return tag == JS_TAG_BIG_INT;
}
static inline JS_BOOL JS_IsBigFloat(JSValueConst v)

34
repl.js
View File

@ -1,8 +1,8 @@
/*
* QuickJS Read Eval Print Loop
*
* Copyright (c) 2017-2019 Fabrice Bellard
* Copyright (c) 2017-2019 Charlie Gordon
* Copyright (c) 2017-2020 Fabrice Bellard
* Copyright (c) 2017-2020 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -860,18 +860,6 @@ import * as os from "os";
var hex_mode = false;
var eval_mode = "std";
function bignum_typeof(a) {
"use bigint";
return typeof a;
}
function eval_mode_typeof(a) {
if (eval_mode === "std")
return typeof a;
else
return bignum_typeof(a);
}
function number_to_string(a, radix) {
var s;
if (!isFinite(a)) {
@ -897,13 +885,6 @@ import * as os from "os";
s = a.toString();
}
}
if (eval_mode !== "std" && s.indexOf(".") < 0 &&
((radix == 16 && s.indexOf("p") < 0) ||
(radix == 10 && s.indexOf("e") < 0))) {
/* add a decimal point so that the floating point type
is visible */
s += ".0";
}
return s;
}
}
@ -975,7 +956,7 @@ import * as os from "os";
function print_rec(a) {
var n, i, keys, key, type, s;
type = eval_mode_typeof(a);
type = typeof(a);
if (type === "object") {
if (a === null) {
std.puts(a);
@ -1037,7 +1018,7 @@ import * as os from "os";
} else if (type === "bigfloat") {
std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
} else if (type === "bigdecimal") {
std.puts(a.toString() + "d");
std.puts(a.toString() + "m");
} else if (type === "symbol") {
std.puts(String(a));
} else if (type === "function") {
@ -1133,8 +1114,7 @@ import * as os from "os";
param = expr.substring(cmd.length + 1).trim();
if (param === "") {
std.puts("Running mode=" + eval_mode + "\n");
} else if (param === "std" || param === "math" ||
param === "bigint") {
} else if (param === "std" || param === "math") {
eval_mode = param;
} else {
std.puts("Invalid mode\n");
@ -1192,7 +1172,7 @@ import * as os from "os";
std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
"\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
if (!has_jscalc) {
std.puts("\\mode [std|bigint|math] change the running mode (current = " + eval_mode + ")\n");
std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
}
}
if (!config_numcalc) {
@ -1206,8 +1186,6 @@ import * as os from "os";
try {
if (eval_mode === "math")
expr = '"use math"; void 0;' + expr;
else if (eval_mode === "bigint")
expr = '"use bigint"; void 0;' + expr;
var now = (new Date).getTime();
/* eval as a script */
result = std.evalScript(expr, { backtrace_barrier: true });

View File

@ -1,4 +1,17 @@
test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/class/super-evaluation-order.js:26: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
test262/test/language/expressions/class/super-evaluation-order.js:26: strict mode: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:32: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all

View File

@ -171,67 +171,152 @@ function test_bigfloat()
e = new BigFloatEnv(128);
assert(e.prec == 128);
a = BigFloat.sqrt(2l, e);
assert(a == BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
assert(e.inexact === true);
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
assert(a == b);
assert(a === b);
assert(BigFloat.isNaN(BigFloat(NaN)));
assert(BigFloat.isFinite(1l));
assert(!BigFloat.isFinite(1l/0l));
assert(BigFloat.abs(-3l) === 3l);
assert(BigFloat.sign(-3l) === -1l);
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
assert(BigFloat.floor(2.5l) === 2l);
assert(BigFloat.ceil(2.5l) === 3l);
assert(BigFloat.trunc(-2.5l) === -2l);
assert(BigFloat.round(2.5l) === 3l);
assert(BigFloat.fmod(3l,2l) === 1l);
assert(BigFloat.remainder(3l,2l) === -1l);
/* string conversion */
assert((1234.125l).toString(), "1234.125");
assert((1234.125l).toFixed(2), "1234.13");
assert((1234.125l).toFixed(2, "down"), "1234.12");
assert((1234.125l).toExponential(), "1.234125e+3");
assert((1234.125l).toExponential(5), "1.23413e+3");
assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
assert((1234.125l).toPrecision(6), "1234.13");
assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
/* string conversion with binary base */
assert((0x123.438l).toString(16), "123.438");
assert((0x323.438l).toString(16), "323.438");
assert((0x723.438l).toString(16), "723.438");
assert((0xf23.438l).toString(16), "f23.438");
assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
}
function test_bigdecimal()
{
assert(1d === 1d);
assert(1d !== 2d);
test_less(1d, 2d);
test_eq(2d, 2d);
assert(1m === 1m);
assert(1m !== 2m);
test_less(1m, 2m);
test_eq(2m, 2m);
test_less(1, 2d);
test_eq(2, 2d);
test_less(1, 2m);
test_eq(2, 2m);
test_less(1.1, 2d);
test_eq(Math.sqrt(4), 2d);
test_less(1.1, 2m);
test_eq(Math.sqrt(4), 2m);
test_less(2n, 3d);
test_eq(3n, 3d);
test_less(2n, 3m);
test_eq(3n, 3m);
assert(BigDecimal("1234.1") === 1234.1d);
assert(BigDecimal(" 1234.1") === 1234.1d);
assert(BigDecimal(" 1234.1 ") === 1234.1d);
assert(BigDecimal("1234.1") === 1234.1m);
assert(BigDecimal(" 1234.1") === 1234.1m);
assert(BigDecimal(" 1234.1 ") === 1234.1m);
assert(BigDecimal(0.1) === 0.1d);
assert(BigDecimal(123) === 123d);
assert(BigDecimal(true) === 1d);
assert(BigDecimal(0.1) === 0.1m);
assert(BigDecimal(123) === 123m);
assert(BigDecimal(true) === 1m);
assert(123d + 1d === 124d);
assert(123d - 1d === 122d);
assert(123m + 1m === 124m);
assert(123m - 1m === 122m);
assert(3.2d * 3d === 9.6d);
assert(10d / 2d === 5d);
assertThrows(RangeError, () => { 10d / 3d } );
assert(BigDecimal.div(20d, 3d,
assert(3.2m * 3m === 9.6m);
assert(10m / 2m === 5m);
assertThrows(RangeError, () => { 10m / 3m } );
assert(10m % 3m === 1m);
assert(-10m % 3m === -1m);
assert(1234.5m ** 3m === 1881365963.625m);
assertThrows(RangeError, () => { 2m ** 3.1m } );
assertThrows(RangeError, () => { 2m ** -3m } );
assert(BigDecimal.sqrt(2m,
{ roundingMode: "half-even",
maximumSignificantDigits: 3 }) === 6.67d);
assert(BigDecimal.div(20d, 3d,
maximumSignificantDigits: 4 }) === 1.414m);
assert(BigDecimal.sqrt(101m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 6.667d);
assert(10d % 3d === 1d);
assert(-10d % 3d === -1d);
assert(-10d % 3d === -1d);
assert(1234.5d ** 3d === 1881365963.625d);
assertThrows(RangeError, () => { 2d ** 3.1d } );
assertThrows(RangeError, () => { 2d ** -3d } );
assert(BigDecimal.sqrt(2d,
maximumFractionDigits: 3 }) === 10.050m);
assert(BigDecimal.sqrt(0.002m,
{ roundingMode: "half-even",
maximumSignificantDigits: 4 }) === 1.414d);
maximumFractionDigits: 3 }) === 0.045m);
assert(BigDecimal.round(3.14159d,
assert(BigDecimal.round(3.14159m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 3.142d);
maximumFractionDigits: 3 }) === 3.142m);
assert(BigDecimal.add(3.14159m, 0.31212m,
{ roundingMode: "half-even",
maximumFractionDigits: 2 }) === 3.45m);
assert(BigDecimal.sub(3.14159m, 0.31212m,
{ roundingMode: "down",
maximumFractionDigits: 2 }) === 2.82m);
assert(BigDecimal.mul(3.14159m, 0.31212m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 0.981m);
assert(BigDecimal.mod(3.14159m, 0.31211m,
{ roundingMode: "half-even",
maximumFractionDigits: 4 }) === 0.0205m);
assert(BigDecimal.div(20m, 3m,
{ roundingMode: "half-even",
maximumSignificantDigits: 3 }) === 6.67m);
assert(BigDecimal.div(20m, 3m,
{ roundingMode: "half-even",
maximumFractionDigits: 50 }) ===
6.66666666666666666666666666666666666666666666666667m);
/* string conversion */
assert((1234.125m).toString(), "1234.125");
assert((1234.125m).toFixed(2), "1234.13");
assert((1234.125m).toFixed(2, "down"), "1234.12");
assert((1234.125m).toExponential(), "1.234125e+3");
assert((1234.125m).toExponential(5), "1.23413e+3");
assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
assert((1234.125m).toPrecision(6), "1234.13");
assert((1234.125m).toPrecision(6, "down"), "1234.12");
assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
}
test_bigint1();

View File

@ -0,0 +1,207 @@
"use strict";
function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;
if (actual === expected)
return;
if (actual !== null && expected !== null
&& typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString())
return;
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
}
/* operators overloading with Operators.create() */
function test_operators_create() {
class Vec2
{
constructor(x, y) {
this.x = x;
this.y = y;
}
static mul_scalar(p1, a) {
var r = new Vec2();
r.x = p1.x * a;
r.y = p1.y * a;
return r;
}
toString() {
return "Vec2(" + this.x + "," + this.y + ")";
}
}
Vec2.prototype[Symbol.operatorSet] = Operators.create(
{
"+"(p1, p2) {
var r = new Vec2();
r.x = p1.x + p2.x;
r.y = p1.y + p2.y;
return r;
},
"-"(p1, p2) {
var r = new Vec2();
r.x = p1.x - p2.x;
r.y = p1.y - p2.y;
return r;
},
"=="(a, b) {
return a.x == b.x && a.y == b.y;
},
"<"(a, b) {
var r;
/* lexicographic order */
if (a.x == b.x)
r = (a.y < b.y);
else
r = (a.x < b.x);
return r;
},
"++"(a) {
var r = new Vec2();
r.x = a.x + 1;
r.y = a.y + 1;
return r;
}
},
{
left: Number,
"*"(a, b) {
return Vec2.mul_scalar(b, a);
}
},
{
right: Number,
"*"(a, b) {
return Vec2.mul_scalar(a, b);
}
});
var a = new Vec2(1, 2);
var b = new Vec2(3, 4);
var r;
r = a * 2 + 3 * b;
assert(r.x === 11 && r.y === 16);
assert(a == a, true);
assert(a == b, false);
assert(a != a, false);
assert(a < b, true);
assert(a <= b, true);
assert(b < a, false);
assert(b <= a, false);
assert(a <= a, true);
assert(a >= a, true);
a++;
assert(a.x === 2 && a.y === 3);
r = ++a;
assert(a.x === 3 && a.y === 4);
assert(r === a);
}
/* operators overloading thru inheritance */
function test_operators()
{
var Vec2;
function mul_scalar(p1, a) {
var r = new Vec2();
r.x = p1.x * a;
r.y = p1.y * a;
return r;
}
var vec2_ops = Operators({
"+"(p1, p2) {
var r = new Vec2();
r.x = p1.x + p2.x;
r.y = p1.y + p2.y;
return r;
},
"-"(p1, p2) {
var r = new Vec2();
r.x = p1.x - p2.x;
r.y = p1.y - p2.y;
return r;
},
"=="(a, b) {
return a.x == b.x && a.y == b.y;
},
"<"(a, b) {
var r;
/* lexicographic order */
if (a.x == b.x)
r = (a.y < b.y);
else
r = (a.x < b.x);
return r;
},
"++"(a) {
var r = new Vec2();
r.x = a.x + 1;
r.y = a.y + 1;
return r;
}
},
{
left: Number,
"*"(a, b) {
return mul_scalar(b, a);
}
},
{
right: Number,
"*"(a, b) {
return mul_scalar(a, b);
}
});
Vec2 = class Vec2 extends vec2_ops
{
constructor(x, y) {
super();
this.x = x;
this.y = y;
}
toString() {
return "Vec2(" + this.x + "," + this.y + ")";
}
}
var a = new Vec2(1, 2);
var b = new Vec2(3, 4);
var r;
r = a * 2 + 3 * b;
assert(r.x === 11 && r.y === 16);
assert(a == a, true);
assert(a == b, false);
assert(a != a, false);
assert(a < b, true);
assert(a <= b, true);
assert(b < a, false);
assert(b <= a, false);
assert(a <= a, true);
assert(a >= a, true);
a++;
assert(a.x === 2 && a.y === 3);
r = ++a;
assert(a.x === 3 && a.y === 4);
assert(r === a);
}
function test_default_op()
{
assert(Object(1) + 2, 3);
assert(Object(1) + true, 2);
assert(-Object(1), -1);
}
test_operators_create();
test_operators();
test_default_op();

View File

@ -66,13 +66,14 @@ function test_integer()
r = (1 << 31) < 0;
assert(r, false, "(1 << 31) < 0 === false");
assert(typeof 1 === "number");
assert(typeof 9007199254740991 === "number");
assert(typeof 9007199254740992 === "bigint");
}
function test_float()
{
var e, a, b, sqrt2;
assert(typeof 1 === "bigint");
assert(typeof 1.0 === "bigfloat");
assert(1 == 1.0);
assert(1 !== 1.0);
@ -101,6 +102,16 @@ function test_modulo()
assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
}
function test_fraction()
{
assert((1/3 + 1).toString(), "4/3")
assert((2/3)^30, 1073741824/205891132094649);
assert(1/3 < 2/3);
assert(1/3 < 1);
assert(1/3 == 1.0/3);
assert(1.0/3 < 2/3);
}
function test_mod()
{
var a, b, p;
@ -235,6 +246,7 @@ test_integer();
test_float();
test_modulo();
test_fraction();
test_mod();
test_polynomial();
test_poly_mod();