mirror of
https://github.com/bellard/quickjs
synced 2024-11-27 08:09:40 +03:00
2020-01-19 release
This commit is contained in:
parent
91459fb672
commit
0e8fffd4de
12
Changelog
12
Changelog
@ -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.
|
||||
|
34
Makefile
34
Makefile
@ -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
|
||||
@ -215,7 +224,7 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
endif # CONFIG_LTO
|
||||
|
||||
repl.c: $(QJSC) repl.js
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -c -o $@ -m repl.js
|
||||
|
||||
qjscalc.c: $(QJSC) qjscalc.js
|
||||
@ -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
5
TODO
@ -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
|
||||
|
@ -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>&</code></dt>
|
||||
<dd><p><code>Symbol.operatorAnd</code>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code><<</code></dt>
|
||||
<dd><p><code>Symbol.operatorShl</code>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>>></code></dt>
|
||||
<dd><p><code>Symbol.operatorShr</code>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code><</code></dt>
|
||||
<dd><p><code>Symbol.operatorCmpLT</code>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>></code></dt>
|
||||
<dd><p><code>Symbol.operatorCmpLT</code>, operands swapped
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code><=</code></dt>
|
||||
<dd><p><code>Symbol.operatorCmpLE</code>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>>=</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>"use bigint"</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 === "number"</code> and <code>typeof 1 === "bigint"</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 << 32 === 4294967296</code> while it gives <code>1</code> in standard mode. However, the <code>>>></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>"integer"</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 < 0</em> returns a Float in bigint mode. In math mode, <code>BigInt[Symbol.operatorPow]</code> is invoked.
|
||||
|
||||
</li><li> <em>b >= 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><<</code> and <code><<</code>, the shift can be positive or negative. So
|
||||
<code>a << b</code> is defined as <em>\lfloor a/2^{-b} \rfloor</em> and
|
||||
<code>a >> b</code> is defined as <em>\lfloor a/2^{b} \rfloor</em>.
|
||||
</p>
|
||||
<p>The operator <code>>>></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 <, <=, >, >=, ==, != 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 < 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 < 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> (“round to nearest with ties to even”)<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> (“round to nearest with ties to even”)<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 <
|
||||
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 >= 53 and <code>e</code> must be >= 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><=</code></dt>
|
||||
<dt><code>>=</code></dt>
|
||||
<dt><code><</code></dt>
|
||||
<dt><code>></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>"floor"</code>, <code>"ceiling"</code>, <code>"down"</code>, <code>"up"</code>,
|
||||
<code>"half-even"</code>, <code>"half-up"</code>). Either
|
||||
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> 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).
|
||||
</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 = "half-up")</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = "half-up")</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>"use math"</code>
|
||||
directive. <code>"use bigint"</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 === "bigfloat"</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 === "number "</code>, <code>typeof 1n === "number"</code> but <code>typeof 9007199254740992 === "bigint" </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>
|
||||
|
BIN
doc/jsbignum.pdf
BIN
doc/jsbignum.pdf
Binary file not shown.
@ -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
|
||||
|
@ -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>"use bigint"</code> and <code>"use math"</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>
|
||||
|
BIN
doc/quickjs.pdf
BIN
doc/quickjs.pdf
Binary file not shown.
@ -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.
|
||||
|
||||
|
@ -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"));
|
||||
})();
|
||||
|
119
libbf.h
119
libbf.h
@ -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
26
qjs.c
@ -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
24
qjsc.c
@ -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++) {
|
||||
|
1439
qjscalc.js
1439
qjscalc.js
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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 ),
|
||||
|
@ -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 */
|
||||
|
||||
|
18
quickjs.h
18
quickjs.h
@ -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
34
repl.js
@ -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 });
|
||||
|
@ -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
|
||||
|
@ -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 } );
|
||||
maximumFractionDigits: 3 }) === 10.050m);
|
||||
assert(BigDecimal.sqrt(0.002m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 0.045m);
|
||||
|
||||
assert(BigDecimal.sqrt(2d,
|
||||
assert(BigDecimal.round(3.14159m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 4 }) === 1.414d);
|
||||
|
||||
assert(BigDecimal.round(3.14159d,
|
||||
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",
|
||||
maximumFractionDigits: 3 }) === 3.142d);
|
||||
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();
|
||||
|
207
tests/test_op_overloading.js
Normal file
207
tests/test_op_overloading.js
Normal 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();
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user