History

2020-01-19 release

bellard committed 6 years ago

Commit 0e8fffd1 parent 91459fb26 files · +4264 −3605Browse files

Unified · Split

26 files
  1. Changelog +12 −0
  2. Makefile +28 −6
  3. TODO +2 −3
  4. VERSION +1 −1
  5. doc/jsbignum.html +223 −531
  6. doc/jsbignum.pdf +0 −0
  7. doc/jsbignum.texi +179 −422
  8. doc/quickjs.html +12 −3
  9. doc/quickjs.pdf +0 −0
  10. doc/quickjs.texi +8 −1
  11. examples/pi_bigdecimal.js +8 −10
  12. libbf.c +677 −439
  13. libbf.h +77 −42
  14. qjs.c +22 −4
  15. qjsc.c +16 −8
  16. qjscalc.js +817 −618
  17. quickjs-atom.h +4 −22
  18. quickjs-libc.c +15 −0
  19. quickjs-opcode.h +0 −3
  20. quickjs.c +1788 −1418
  21. quickjs.h +11 −5
  22. repl.js +6 −28
  23. test262_errors.txt +13 −0
  24. tests/test_bignum.js +125 −40
  25. tests/test_op_overloading.js +207 −0
  26. tests/test_qjscalc.js +15 −3
Changelog+12−0
@@ -1,3 +1,15 @@
12020-01-19:
2
3- keep CONFIG_BIGNUM in the makefile
4- added os.chdir()
5- qjs: added -I option
6- more memory checks in the bignum operations
7- modified operator overloading semantics to be closer to the TC39
8 proposal
9- suppressed "use bigint" mode. Simplified "use math" mode
10- BigDecimal: changed suffix from 'd' to 'm'
11- misc bug fixes
12
12020-01-05:132020-01-05:
2 14
3- always compile the bignum code. Added '--bignum' option to qjs.15- always compile the bignum code. Added '--bignum' option to qjs.
Makefile+28−6
@@ -1,8 +1,8 @@
1#1#
2# QuickJS Javascript Engine2# QuickJS Javascript Engine
3# 3#
4# Copyright (c) 2017-2019 Fabrice Bellard4# Copyright (c) 2017-2020 Fabrice Bellard
5# Copyright (c) 2017-2019 Charlie Gordon5# Copyright (c) 2017-2020 Charlie Gordon
6#6#
7# Permission is hereby granted, free of charge, to any person obtaining a copy7# Permission is hereby granted, free of charge, to any person obtaining a copy
8# of this software and associated documentation files (the "Software"), to deal8# of this software and associated documentation files (the "Software"), to deal
@@ -47,6 +47,8 @@ prefix=/usr/local · 38 unmodified lines
47#CONFIG_PROFILE=y47#CONFIG_PROFILE=y
48# use address sanitizer48# use address sanitizer
49#CONFIG_ASAN=y49#CONFIG_ASAN=y
50# include the code for BigInt/BigFloat/BigDecimal and math mode
51CONFIG_BIGNUM=y
50 52
51OBJDIR=.obj53OBJDIR=.obj
52 54
@@ -94,6 +96,9 @@ ifdef CONFIG_WERROR · 41 unmodified lines
94CFLAGS+=-Werror96CFLAGS+=-Werror
95endif97endif
96DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"98DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
99ifdef CONFIG_BIGNUM
100DEFINES+=-DCONFIG_BIGNUM
101endif
97CFLAGS+=$(DEFINES)102CFLAGS+=$(DEFINES)
98CFLAGS_DEBUG=$(CFLAGS) -O0103CFLAGS_DEBUG=$(CFLAGS) -O0
99CFLAGS_SMALL=$(CFLAGS) -Os104CFLAGS_SMALL=$(CFLAGS) -Os
@@ -153,9 +158,13 @@ endif · 53 unmodified lines
153 158
154all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)159all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
155 160
156QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/libbf.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o161QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
157 162
158QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(OBJDIR)/qjscalc.o $(QJS_LIB_OBJS)163QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
164ifdef CONFIG_BIGNUM
165QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
166QJS_OBJS+=$(OBJDIR)/qjscalc.o
167endif
159 168
160LIBS=-lm169LIBS=-lm
161ifndef CONFIG_WIN32170ifndef CONFIG_WIN32
@@ -215,7 +224,7 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) · 53 unmodified lines
215 $(AR) rcs $@ $^224 $(AR) rcs $@ $^
216endif # CONFIG_LTO225endif # CONFIG_LTO
217 226
218repl.c: $(QJSC) repl.js 227repl.c: $(QJSC) repl.js
219 $(QJSC) -c -o $@ -m repl.js228 $(QJSC) -c -o $@ -m repl.js
220 229
221qjscalc.c: $(QJSC) qjscalc.js230qjscalc.c: $(QJSC) qjscalc.js
@@ -301,7 +310,10 @@ endif · 79 unmodified lines
301HELLO_SRCS=examples/hello.js310HELLO_SRCS=examples/hello.js
302HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \311HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
303 -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \312 -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
304 -fno-date -fno-module-loader -fno-bigint313 -fno-date -fno-module-loader
314ifdef CONFIG_BIGNUM
315HELLO_OPTS+=-fno-bigint
316endif
305 317
306hello.c: $(QJSC) $(HELLO_SRCS)318hello.c: $(QJSC) $(HELLO_SRCS)
307 $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)319 $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
@@ -372,20 +384,30 @@ test: qjs · 64 unmodified lines
372 ./qjs tests/test_loop.js384 ./qjs tests/test_loop.js
373 ./qjs tests/test_std.js385 ./qjs tests/test_std.js
374ifndef CONFIG_DARWIN386ifndef CONFIG_DARWIN
387ifdef CONFIG_BIGNUM
375 ./qjs --bignum tests/test_bjson.js388 ./qjs --bignum tests/test_bjson.js
389else
390 ./qjs tests/test_bjson.js
391endif
376 ./qjs examples/test_point.js392 ./qjs examples/test_point.js
377endif393endif
394ifdef CONFIG_BIGNUM
395 ./qjs --bignum tests/test_op_overloading.js
378 ./qjs --bignum tests/test_bignum.js396 ./qjs --bignum tests/test_bignum.js
379 ./qjs --qjscalc tests/test_qjscalc.js397 ./qjs --qjscalc tests/test_qjscalc.js
398endif
380ifdef CONFIG_M32399ifdef CONFIG_M32
381 ./qjs32 tests/test_closure.js400 ./qjs32 tests/test_closure.js
382 ./qjs32 tests/test_op.js401 ./qjs32 tests/test_op.js
383 ./qjs32 tests/test_builtin.js402 ./qjs32 tests/test_builtin.js
384 ./qjs32 tests/test_loop.js403 ./qjs32 tests/test_loop.js
385 ./qjs32 tests/test_std.js404 ./qjs32 tests/test_std.js
405ifdef CONFIG_BIGNUM
406 ./qjs32 --bignum tests/test_op_overloading.js
386 ./qjs32 --bignum tests/test_bignum.js407 ./qjs32 --bignum tests/test_bignum.js
387 ./qjs32 --qjscalc tests/test_qjscalc.js408 ./qjs32 --qjscalc tests/test_qjscalc.js
388endif409endif
410endif
389 411
390stats: qjs qjs32412stats: qjs qjs32
391 ./qjs -qd413 ./qjs -qd
TODO+2−3
@@ -73,6 +73,5 @@ REPL: · 72 unmodified lines
73Test262o: 0/11262 errors, 463 excluded73Test262o: 0/11262 errors, 463 excluded
74Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)74Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
75 75
76Test262: 4/67619 errors, 913 excluded, 1660 skipped76Test262: 17/69942 errors, 855 excluded, 581 skipped
77Test262bn: 4/69722 errors, 846 excluded, 672 skipped77test262 commit: 28b4fcca4b1b1d278dfe0cc0e69c7d9d59b31aab
78test262 commit: 19fd4bea797646ae9bbfc9d325f14052ca370b54
VERSION+1−1
@@ -1 +1 @@
12020-01-0512020-01-19
doc/jsbignum.html+223−531
@@ -1,7 +1,8 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2<html>2<html>
3<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->3<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
4<head>4<head>
5<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5<title>Javascript Bignum Extensions</title>6<title>Javascript Bignum Extensions</title>
6 7
7<meta name="description" content="Javascript Bignum Extensions">8<meta name="description" content="Javascript Bignum Extensions">
@@ -9,7 +10,6 @@ · 1 unmodified line
9<meta name="resource-type" content="document">10<meta name="resource-type" content="document">
10<meta name="distribution" content="global">11<meta name="distribution" content="global">
11<meta name="Generator" content="makeinfo">12<meta name="Generator" content="makeinfo">
12<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
13<link href="#SEC_Contents" rel="contents" title="Table of Contents">13<link href="#SEC_Contents" rel="contents" title="Table of Contents">
14<style type="text/css">14<style type="text/css">
15<!--15<!--
@@ -52,61 +52,33 @@ ul.no-bullet {list-style: none} · 36 unmodified lines
52<div class="contents">52<div class="contents">
53<ul class="no-bullet">53<ul class="no-bullet">
54<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>54<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
55<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a>55<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
56<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
57<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
56<ul class="no-bullet">58<ul class="no-bullet">
57 <li><a name="toc-Introduction-1" href="#Introduction-1">2.1 Introduction</a></li>59 <li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
58 <li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">2.2 Builtin Object changes</a>
59 <ul class="no-bullet">
60 <li><a name="toc-Symbol-constructor" href="#Symbol-constructor">2.2.1 <code>Symbol</code> constructor</a></li>
61 </ul></li>
62</ul></li>
63<li><a name="toc-The-BigInt-Mode" href="#The-BigInt-Mode">3 The BigInt Mode</a>
64<ul class="no-bullet">
65 <li><a name="toc-Introduction-2" href="#Introduction-2">3.1 Introduction</a></li>
66 <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>
67 <ul class="no-bullet">
68 <li><a name="toc-Standard-mode" href="#Standard-mode">3.2.1 Standard mode</a></li>
69 <li><a name="toc-Bigint-mode" href="#Bigint-mode">3.2.2 Bigint mode</a></li>
70 </ul></li>
71 <li><a name="toc-Operators" href="#Operators">3.3 Operators</a>
72 <ul class="no-bullet">
73 <li><a name="toc-Arithmetic-operators" href="#Arithmetic-operators">3.3.1 Arithmetic operators</a></li>
74 <li><a name="toc-Logical-operators" href="#Logical-operators">3.3.2 Logical operators</a></li>
75 <li><a name="toc-Relational-operators" href="#Relational-operators">3.3.3 Relational operators</a></li>
76 </ul></li>
77 <li><a name="toc-Number-literals" href="#Number-literals">3.4 Number literals</a></li>
78 <li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">3.5 Builtin Object changes</a>
79 <ul class="no-bullet">
80 <li><a name="toc-BigInt-function" href="#BigInt-function">3.5.1 <code>BigInt</code> function</a></li>
81 <li><a name="toc-BigInt_002eprototype" href="#BigInt_002eprototype">3.5.2 <code>BigInt.prototype</code></a></li>
82 <li><a name="toc-Number-constructor" href="#Number-constructor">3.5.3 <code>Number</code> constructor</a></li>
83 <li><a name="toc-Number_002eprototype" href="#Number_002eprototype">3.5.4 <code>Number.prototype</code></a></li>
84 <li><a name="toc-Math-object" href="#Math-object">3.5.5 <code>Math</code> object</a></li>
85 </ul></li>
86</ul></li>
87<li><a name="toc-Arbitrarily-large-floating-point-numbers" href="#Arbitrarily-large-floating-point-numbers">4 Arbitrarily large floating point numbers</a>
88<ul class="no-bullet">
89 <li><a name="toc-Introduction-3" href="#Introduction-3">4.1 Introduction</a></li>
90 <li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>60 <li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
91 <li><a name="toc-Operators-1" href="#Operators-1">4.3 Operators</a></li>61 <li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
92 <li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>62 <li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
93 <li><a name="toc-Builtin-Object-changes-2" href="#Builtin-Object-changes-2">4.5 Builtin Object changes</a>63 <li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
94 <ul class="no-bullet">64 <ul class="no-bullet">
95 <li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>65 <li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
96 <li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>66 <li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
97 <li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>67 <li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
98 <li><a name="toc-Math-object-1" href="#Math-object-1">4.5.4 <code>Math</code> object</a></li>
99 </ul></li>68 </ul></li>
100</ul></li>69</ul></li>
101<li><a name="toc-Math-mode" href="#Math-mode">5 Math mode</a>70<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
102<ul class="no-bullet">71<ul class="no-bullet">
103 <li><a name="toc-Introduction-4" href="#Introduction-4">5.1 Introduction</a></li>72 <li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
104 <li><a name="toc-Builtin-Object-changes-3" href="#Builtin-Object-changes-3">5.2 Builtin Object changes</a>73 <li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
74 <li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
105 <ul class="no-bullet">75 <ul class="no-bullet">
106 <li><a name="toc-Symbol-constructor-1" href="#Symbol-constructor-1">5.2.1 <code>Symbol</code> constructor</a></li>76 <li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
77 <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>
78 <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>
107 </ul></li>79 </ul></li>
108 <li><a name="toc-Remaining-issues" href="#Remaining-issues">5.3 Remaining issues</a></li>
109</ul></li>80</ul></li>
81<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
110 82
111</ul>83</ul>
112</div>84</div>
@@ -119,379 +91,52 @@ ul.no-bullet {list-style: none} · 6 unmodified lines
119language while being 100% backward compatible:91language while being 100% backward compatible:
120</p>92</p>
121<ul>93<ul>
122<li> Overloading of the standard operators94<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>.
123to support new types such as complex numbers, fractions or matrices.
124
125</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>).
126 95
127</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.96</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
128 97
129</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.98</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
99<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
100
101</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
102remainder. <code>^</code> is an alias to the power operator
103(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
130 104
131</li></ul>105</li></ul>
132 106
133<p>The extensions are independent from each other except the <code>math</code>107<p>The extensions are independent from each other except the <code>math</code>
134mode which relies on the bigint mode and the operator overloading.108mode which relies on BigFloat and operator overloading.
135</p>109</p>
136<a name="Operator-overloading"></a>110<a name="Operator-overloading"></a>
137<h2 class="chapter">2 Operator overloading</h2>111<h2 class="chapter">2 Operator overloading</h2>
138 112
139<a name="Introduction-1"></a>113<p>Operator overloading is inspired from the proposal available at
140<h3 class="section">2.1 Introduction</h3>114<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
141 115implements the same dispatch logic but finds the operator sets by
142<p>If the operands of an operator have at least one object type, a custom116looking at the <code>Symbol.operatorSet</code> property in the objects. The
143operator method is searched before doing the legacy Javascript117changes were done in order to simplify the implementation.
144<code>ToNumber</code> conversion.
145</p>
146<p>For unary operators, the custom function is looked up in the object
147and has the following name:
148</p>
149<dl compact="compact">
150<dt><code>unary +</code></dt>
151<dd><p><code>Symbol.operatorPlus</code>
152</p>
153</dd>
154<dt><code>unary -</code></dt>
155<dd><p><code>Symbol.operatorNeg</code>
156</p>
157</dd>
158<dt><code>++</code></dt>
159<dd><p><code>Symbol.operatorInc</code>
160</p>
161</dd>
162<dt><code>--</code></dt>
163<dd><p><code>Symbol.operatorDec</code>
164</p>
165</dd>
166<dt><code>~</code></dt>
167<dd><p><code>Symbol.operatorNot</code>
168</p>
169</dd>
170</dl>
171
172<p>For binary operators:
173</p>
174<ul>
175<li> If both operands have the same constructor function, then the operator
176is looked up in the constructor.
177
178</li><li> Otherwise, the property <code>Symbol.operatorOrder</code> is looked up in both
179constructors and converted to <code>Int32</code>. The operator is then
180looked in the constructor with the larger <code>Symbol.operatorOrder</code>
181value. A <code>TypeError</code> is raised if both constructors have the same
182<code>Symbol.operatorOrder</code> value.
183
184</li></ul>
185
186<p>The operator is looked up with the following name:
187</p>
188<dl compact="compact">
189<dt><code>+</code></dt>
190<dd><p><code>Symbol.operatorAdd</code>
191</p>
192</dd>
193<dt><code>-</code></dt>
194<dd><p><code>Symbol.operatorSub</code>
195</p>
196</dd>
197<dt><code>*</code></dt>
198<dd><p><code>Symbol.operatorMul</code>
199</p>
200</dd>
201<dt><code>/</code></dt>
202<dd><p><code>Symbol.operatorDiv</code>
203</p>
204</dd>
205<dt><code>%</code></dt>
206<dd><p><code>Symbol.operatorMod</code>
207</p>
208</dd>
209<dt><code>% (math mode)</code></dt>
210<dd><p><code>Symbol.operatorMathMod</code>
211</p>
212</dd>
213<dt><code>**</code></dt>
214<dd><p><code>Symbol.operatorPow</code>
215</p>
216</dd>
217<dt><code>|</code></dt>
218<dd><p><code>Symbol.operatorOr</code>
219</p>
220</dd>
221<dt><code>^</code></dt>
222<dd><p><code>Symbol.operatorXor</code>
223</p>
224</dd>
225<dt><code>&amp;</code></dt>
226<dd><p><code>Symbol.operatorAnd</code>
227</p>
228</dd>
229<dt><code>&lt;&lt;</code></dt>
230<dd><p><code>Symbol.operatorShl</code>
231</p>
232</dd>
233<dt><code>&gt;&gt;</code></dt>
234<dd><p><code>Symbol.operatorShr</code>
235</p>
236</dd>
237<dt><code>&lt;</code></dt>
238<dd><p><code>Symbol.operatorCmpLT</code>
239</p>
240</dd>
241<dt><code>&gt;</code></dt>
242<dd><p><code>Symbol.operatorCmpLT</code>, operands swapped
243</p>
244</dd>
245<dt><code>&lt;=</code></dt>
246<dd><p><code>Symbol.operatorCmpLE</code>
247</p>
248</dd>
249<dt><code>&gt;=</code></dt>
250<dd><p><code>Symbol.operatorCmpLE</code>, operands swapped
251</p>
252</dd>
253<dt><code>==, !=</code></dt>
254<dd><p><code>Symbol.operatorCmpEQ</code>
255</p>
256</dd>
257</dl>
258
259<p>The return value of <code>Symbol.operatorCmpLT</code>, <code>Symbol.operatorCmpLE</code> and
260<code>Symbol.operatorCmpEQ</code> is converted to <code>Boolean</code>.
261</p>118</p>
262<a name="Builtin-Object-changes"></a>119<p>More precisely, the following modifications were made:
263<h3 class="section">2.2 Builtin Object changes</h3>
264
265<a name="Symbol-constructor"></a>
266<h4 class="subsection">2.2.1 <code>Symbol</code> constructor</h4>
267
268<p>The following global symbols are added for the operator overloading:
269</p><dl compact="compact">
270<dt><code>operatorOrder</code></dt>
271<dt><code>operatorAdd</code></dt>
272<dt><code>operatorSub</code></dt>
273<dt><code>operatorMul</code></dt>
274<dt><code>operatorDiv</code></dt>
275<dt><code>operatorMod</code></dt>
276<dt><code>operatorPow</code></dt>
277<dt><code>operatorShl</code></dt>
278<dt><code>operatorShr</code></dt>
279<dt><code>operatorAnd</code></dt>
280<dt><code>operatorOr</code></dt>
281<dt><code>operatorXor</code></dt>
282<dt><code>operatorCmpLT</code></dt>
283<dt><code>operatorCmpLE</code></dt>
284<dt><code>operatorCmpEQ</code></dt>
285<dt><code>operatorPlus</code></dt>
286<dt><code>operatorNeg</code></dt>
287<dt><code>operatorNot</code></dt>
288<dt><code>operatorInc</code></dt>
289<dt><code>operatorDec</code></dt>
290</dl>
291
292
293<a name="The-BigInt-Mode"></a>
294<h2 class="chapter">3 The BigInt Mode</h2>
295
296<a name="Introduction-2"></a>
297<h3 class="section">3.1 Introduction</h3>
298
299<p>The bigint mode is enabled with the <code>&quot;use bigint&quot;</code> directive. It
300propagates the same way as the strict mode. In bigint mode, all
301integers are considered as <code>bigint</code> (arbitrarily large integer,
302similar to the TC39 BigInt
303proposal<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>)
304instead of <code>number</code> (floating point number). In order to be able
305to exchange data between standard and bigint modes, numbers are
306internally represented as 3 different types:
307</p>120</p>
308<ul>121<ul>
309<li> Small integer (SmallInt): 32 bit integer<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>.122<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
310 123
311</li><li> Big integer (BigInt): arbitrarily large integer.124</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.
312 125
313</li><li> Floating point number (Float).126</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.
314 127
315</li></ul>128</li><li> <code>[]</code> cannot be overloaded.
316
317<p>In standard mode, the semantics of each operation is modified so that
318when it returns a <code>number</code>, it is either of SmallInt or
319Float. But the difference between SmallInt and Float is not observable
320in standard mode.
321</p>
322<p>In bigint mode, each operation behaves differently whether its
323operands are integer or float. The difference between SmallInt and
324BigInt is not observable (i.e. they are both integers).
325</p>
326<p>The following table summarizes the observable types:
327</p>
328<table>
329<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>
330<tr><td width="30%">SmallInt</td><td width="30%">number</td><td width="30%">bigint</td></tr>
331<tr><td width="30%">BigInt</td><td width="30%">bigint</td><td width="30%">bigint</td></tr>
332<tr><td width="30%">Float</td><td width="30%">number</td><td width="30%">number</td></tr>
333</table>
334
335<a name="Changes-that-introduce-incompatibilities-with-Javascript"></a>
336<h3 class="section">3.2 Changes that introduce incompatibilities with Javascript</h3>
337 129
338<a name="Standard-mode"></a>130</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
339<h4 class="subsection">3.2.1 Standard mode</h4>
340
341<p>There is no incompatibility with Javascript.
342</p>
343<a name="Bigint-mode"></a>
344<h4 class="subsection">3.2.2 Bigint mode</h4>
345
346<p>The following changes are visible:
347</p>
348<ul>
349<li> Integer and Float are different types. Constants are typed. For example: <code>typeof 1.0 === &quot;number&quot;</code> and <code>typeof 1 === &quot;bigint&quot;</code>. Another consequence is that <code>1.0 === 1</code> is false.
350
351</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.
352
353</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.
354
355</li><li> Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with <code>0x1f</code> i.e. <code>1 &lt;&lt; 32 === 4294967296</code> while it gives <code>1</code> in standard mode. However, the <code>&gt;&gt;&gt;</code> operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>.
356
357</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.
358
359</li><li> The <code>ToPrimitive</code> abstract operation is called with the <code>&quot;integer&quot;</code> preferred type when an integer is required (e.g. for bitwise binary or shift operations).
360
361</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.
362
363</li><li> If the TC39 BigInt proposal is supported, there is no observable difference between integers and <code>bigint</code>s.
364 131
365</li></ul>132</li></ul>
366 133
367<a name="Operators"></a>134<a name="BigInt-extensions"></a>
368<h3 class="section">3.3 Operators</h3>135<h2 class="chapter">3 BigInt extensions</h2>
369
370<a name="Arithmetic-operators"></a>
371<h4 class="subsection">3.3.1 Arithmetic operators</h4>
372
373<p>The operands are converted to number values as in normal
374Javascript. Then the general case is that an Integer is returned if
375both operands are Integer. Otherwise, a float is returned.
376</p>
377<p>The <code>+</code> operator also accepts strings as input and behaves like
378standard Javascript in this case.
379</p>
380<p>The binary operator <code>%</code> returns the truncated remainder of the
381division. When the result is an Integer type, a dividend of zero yields a
382RangeError exception.
383</p>
384<p>The binary operator <code>%</code> in math mode returns the Euclidian
385remainder of the division i.e. it is always positive.
386</p>
387<p>The binary operator <code>/</code> returns a float.
388</p>
389<p>The binary operator <code>/</code> in math mode returns a float if one of
390the operands is float. Otherwise, <code>BigInt[Symbol.operatorDiv]</code> is
391invoked.
392</p>
393<p>The returned type of <code>a ** b</code> is Float if <em>a</em> or <em>b</em>
394are Float. If <em>a</em> and <em>b</em> are integers:
395</p><ul>
396<li> <em>b &lt; 0</em> returns a Float in bigint mode. In math mode, <code>BigInt[Symbol.operatorPow]</code> is invoked.
397
398</li><li> <em>b &gt;= 0</em> returns an integer.
399</li></ul>
400
401<p>The unary <code>-</code> and unary <code>+</code> return the same type as their
402operand. They performs no floating point rounding when the result is a
403float.
404</p>
405<p>The unary operators <code>++</code> and <code>--</code> return the same type as
406their operand.
407</p>
408<p>In standard mode:
409</p>
410<p>If the operator returns an Integer and that the result fits a
411SmallInt, it is converted to SmallInt. Otherwise, the Integer is
412converted to a Float.
413</p>
414<p>In bigint mode:
415</p>
416<p>If the operator returns an Integer and that the result fits a
417SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
418</p>
419<a name="Logical-operators"></a>
420<h4 class="subsection">3.3.2 Logical operators</h4>
421
422<p>In standard mode:
423</p>
424<p>The operands have their standard behavior. If the result fits a
425SmallInt it is converted to a SmallInt. Otherwise it is a Float.
426</p>
427<p>In bigint mode:
428</p>
429<p>The operands are converted to integer values. The floating point
430values are converted to integer by rounding them to zero.
431</p>
432<p>The logical operators are defined assuming the integers are
433represented in two complement notation.
434</p>
435<p>For <code>&lt;&lt;</code> and <code>&lt;&lt;</code>, the shift can be positive or negative. So
436<code>a &lt;&lt; b</code> is defined as <em>\lfloor a/2^{-b} \rfloor</em> and
437<code>a &gt;&gt; b</code> is defined as <em>\lfloor a/2^{b} \rfloor</em>.
438</p>
439<p>The operator <code>&gt;&gt;&gt;</code> is supported for backward compatibility and
440behaves the same way as Javascript i.e. implicit conversion to <code>Uint32</code>.
441</p>
442<p>If the result fits a SmallInt it is converted to a SmallInt. Otherwise
443it is a BigInt.
444</p>
445<a name="Relational-operators"></a>
446<h4 class="subsection">3.3.3 Relational operators</h4>
447
448<p>The relational operators &lt;, &lt;=, &gt;, &gt;=, ==, != work as expected with
449integers and floating point numbers (e.g. <code>1.0 == 1</code> is true).
450</p>
451<p>The strict equality operators === and !== have the usual Javascript
452semantics. In particular, different types never equal, so <code>1.0
453=== 1</code> is false.
454</p>
455<a name="Number-literals"></a>
456<h3 class="section">3.4 Number literals</h3>
457 136
458<p>Number literals in bigint mode have a slightly different behavior than137<p>A few properties are added to the BigInt object:
459in standard Javascript:
460</p>
461<ol>
462<li> A number literal without a decimal point or an exponent is considered
463as an Integer. Otherwise it is a Float.
464
465</li><li> Hexadecimal, octal or binary floating point literals are accepted with
466a decimal point or an exponent. The exponent is specified with the
467<code>p</code> letter assuming a base 2. The same convention is used by
468C99. Example: <code>0x1p3</code> is the same as <code>8.0</code>.
469
470</li></ol>
471
472<a name="Builtin-Object-changes-1"></a>
473<h3 class="section">3.5 Builtin Object changes</h3>
474
475<a name="BigInt-function"></a>
476<h4 class="subsection">3.5.1 <code>BigInt</code> function</h4>
477
478<p>The <code>BigInt</code> function cannot be invoked as a constructor. When
479invoked as a function, it converts its first parameter to an
480integer. When a floating point number is given as parameter, it is
481truncated to an integer with infinite precision.
482</p>
483<p><code>BigInt</code> properties:
484</p>138</p>
485<dl compact="compact">139<dl compact="compact">
486<dt><code>asIntN(bits, a)</code></dt>
487<dd><p>Set <em>b=a \pmod{2^{bits}}</em>. Return <em>b</em> if <em>b &lt; 2^{bits-1}</em>
488otherwise <em>b-2^{bits}</em>.
489</p>
490</dd>
491<dt><code>asUintN(bits, a)</code></dt>
492<dd><p>Return <em>a \pmod{2^{bits}}</em>.
493</p>
494</dd>
495<dt><code>tdiv(a, b)</code></dt>140<dt><code>tdiv(a, b)</code></dt>
496<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError141<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
497exception.142exception.
@@ -542,70 +187,10 @@ raised if <em>a &lt; 0</em>. · 44 unmodified lines
542</dd>187</dd>
543</dl>188</dl>
544 189
545<a name="BigInt_002eprototype"></a>190<a name="BigFloat"></a>
546<h4 class="subsection">3.5.2 <code>BigInt.prototype</code></h4>191<h2 class="chapter">4 BigFloat</h2>
547 192
548<p>It is a normal object.193<a name="Introduction-1"></a>
549</p>
550<a name="Number-constructor"></a>
551<h4 class="subsection">3.5.3 <code>Number</code> constructor</h4>
552
553<p>The number constructor returns its argument rounded to a Float using
554the global floating point environment. In bigint mode, the Number
555constructor returns a Float. In standard mode, it returns a SmallInt
556if the value fits it, otherwise a Float.
557</p>
558<a name="Number_002eprototype"></a>
559<h4 class="subsection">3.5.4 <code>Number.prototype</code></h4>
560
561<p>The following properties are modified:
562</p>
563<dl compact="compact">
564<dt><code>toString(radix)</code></dt>
565<dd>
566<p>In bigint mode, integers are converted to the specified radix with
567infinite precision.
568</p>
569</dd>
570<dt><code>toPrecision(p)</code></dt>
571<dt><code>toFixed(p)</code></dt>
572<dt><code>toExponential(p)</code></dt>
573<dd>
574<p>In bigint mode, integers are accepted and converted to string with
575infinite precision.
576</p>
577</dd>
578<dt><code>parseInt(string, radix)</code></dt>
579<dd>
580<p>In bigint mode, an integer is returned and the conversion is done with
581infinite precision.
582</p>
583</dd>
584</dl>
585
586<a name="Math-object"></a>
587<h4 class="subsection">3.5.5 <code>Math</code> object</h4>
588
589<p>The following properties are modified:
590</p>
591<dl compact="compact">
592<dt><code>abs(x)</code></dt>
593<dd><p>Absolute value. Return an integer if <code>x</code> is an Integer. Otherwise
594return a Float. No rounding is performed.
595</p>
596</dd>
597<dt><code>min(a, b)</code></dt>
598<dt><code>max(a, b)</code></dt>
599<dd><p>No rounding is performed. The returned type is the same one as the
600minimum (resp. maximum) value.
601</p>
602</dd>
603</dl>
604
605<a name="Arbitrarily-large-floating-point-numbers"></a>
606<h2 class="chapter">4 Arbitrarily large floating point numbers</h2>
607
608<a name="Introduction-3"></a>
609<h3 class="section">4.1 Introduction</h3>194<h3 class="section">4.1 Introduction</h3>
610 195
611<p>This extension adds the <code>BigFloat</code> primitive type. The196<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. · 16 unmodified lines
628point environment is used.213point environment is used.
629</p>214</p>
630<p>The rounding mode of the global floating point environment is always215<p>The rounding mode of the global floating point environment is always
631<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF5" href="#FOOT5"><sup>5</sup></a>. The status flags of the global environment cannot be216<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
632read<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>. The precision of the global environment is217read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
633<code>BigFloatEnv.prec</code>. The number of exponent bits of the global218<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
634environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is219environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is
635strictly smaller than the maximum allowed number of exponent bits220strictly smaller than the maximum allowed number of exponent bits
@@ -646,7 +231,7 @@ when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a · 10 unmodified lines
646function can change the global floating point environment for its231function can change the global floating point environment for its
647callees but not for its caller.232callees but not for its caller.
648</p>233</p>
649<a name="Operators-1"></a>234<a name="Operators"></a>
650<h3 class="section">4.3 Operators</h3>235<h3 class="section">4.3 Operators</h3>
651 236
652<p>The builtin operators are extended so that a BigFloat is returned if237<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 === · 16 unmodified lines
669<p>BigFloat literals are floating point numbers with a trailing <code>l</code>254<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
670suffix. BigFloat literals have an infinite precision. They are rounded255suffix. BigFloat literals have an infinite precision. They are rounded
671according to the global floating point environment when they are256according to the global floating point environment when they are
672evaluated.<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>257evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
673</p>258</p>
674<a name="Builtin-Object-changes-2"></a>259<a name="Builtin-Object-changes"></a>
675<h3 class="section">4.5 Builtin Object changes</h3>260<h3 class="section">4.5 Builtin Object changes</h3>
676 261
677<a name="BigFloat-function"></a>262<a name="BigFloat-function"></a>
@@ -739,6 +324,10 @@ point number <code>a</code> according to the floating point environment · 61 unmodified lines
739<dd><p>Round to an integer. No additional rounding is performed.324<dd><p>Round to an integer. No additional rounding is performed.
740</p>325</p>
741</dd>326</dd>
327<dt><code>abs(x)</code></dt>
328<dd><p>Return the absolute value of x. No additional rounding is performed.
329</p>
330</dd>
742<dt><code>fmod(x, y[, e])</code></dt>331<dt><code>fmod(x, y[, e])</code></dt>
743<dt><code>remainder(x, y[, e])</code></dt>332<dt><code>remainder(x, y[, e])</code></dt>
744<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or333<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. · 28 unmodified lines
773<p>The following properties are modified:362<p>The following properties are modified:
774</p>363</p>
775<dl compact="compact">364<dl compact="compact">
365<dt><code>valueOf()</code></dt>
366<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
367</p>
368</dd>
776<dt><code>toString(radix)</code></dt>369<dt><code>toString(radix)</code></dt>
777<dd>370<dd>
778<p>For floating point numbers:371<p>For floating point numbers:
@@ -787,14 +380,17 @@ the global precision and round to nearest gives the same number. · 8 unmodified lines
787 380
788</li></ul>381</li></ul>
789 382
383<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
38416 with a binary exponent and <code>@</code> for the other bases.
385</p>
790</dd>386</dd>
791<dt><code>toPrecision(p[, rnd_mode])</code></dt>387<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
792<dt><code>toFixed(p[, rnd_mode])</code></dt>388<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
793<dt><code>toExponential(p[, rnd_mode])</code></dt>389<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
794<dd><p>Same semantics as the corresponding <code>Number</code> functions with390<dd><p>Same semantics as the corresponding <code>Number</code> functions with
795BigFloats. There is no limit on the accepted precision <code>p</code>. The391BigFloats. There is no limit on the accepted precision <code>p</code>. The
796rounding mode can be optionally specified. It is set by default to392rounding mode and radix can be optionally specified. The radix must be
797<code>BigFloatEnv.RNDNA</code>.393between 2 and 36.
798</p>394</p>
799</dd>395</dd>
800</dl>396</dl>
@@ -832,14 +428,14 @@ subnormal flags is set to <code>false</code>. If <code>rndMode</code> is · 31 unmodified lines
832<dl compact="compact">428<dl compact="compact">
833<dt><code>prec</code></dt>429<dt><code>prec</code></dt>
834<dd><p>Getter. Return the precision in bits of the global floating point430<dd><p>Getter. Return the precision in bits of the global floating point
835environment. The initial value is <code>53</code>.431environment. The initial value is <code>113</code>.
836</p>432</p>
837</dd>433</dd>
838<dt><code>expBits</code></dt>434<dt><code>expBits</code></dt>
839<dd><p>Getter. Return the exponent size in bits of the global floating point435<dd><p>Getter. Return the exponent size in bits of the global floating point
840environment assuming an IEEE 754 representation. If <code>expBits &lt;436environment assuming an IEEE 754 representation. If <code>expBits &lt;
841expBitsMax</code>, then subnormal numbers are supported. The initial value437expBitsMax</code>, then subnormal numbers are supported. The initial value
842is <code>11</code>.438is <code>15</code>.
843</p>439</p>
844</dd>440</dd>
845<dt><code>setPrec(f, p[, e])</code></dt>441<dt><code>setPrec(f, p[, e])</code></dt>
@@ -848,9 +444,7 @@ and the exponent size to <code>e</code> then call the function · 2 unmodified lines
848<code>f</code>. Then the Float precision and exponent size are reset to444<code>f</code>. Then the Float precision and exponent size are reset to
849their precious value and the return value of <code>f</code> is returned (or445their precious value and the return value of <code>f</code> is returned (or
850an exception is raised if <code>f</code> raised an exception). If <code>e</code>446an exception is raised if <code>f</code> raised an exception). If <code>e</code>
851is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>. <code>p</code>447is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
852must be &gt;= 53 and <code>e</code> must be &gt;= 11 so that the global precision
853is at least equivalent to the IEEE 754 64 bit doubles.
854</p>448</p>
855</dd>449</dd>
856<dt><code>precMin</code></dt>450<dt><code>precMin</code></dt>
@@ -858,7 +452,7 @@ is at least equivalent to the IEEE 754 64 bit doubles. · 1 unmodified line
858</p>452</p>
859</dd>453</dd>
860<dt><code>precMax</code></dt>454<dt><code>precMax</code></dt>
861<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 53.455<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
862</p>456</p>
863</dd>457</dd>
864<dt><code>expBitsMin</code></dt>458<dt><code>expBitsMin</code></dt>
@@ -868,7 +462,7 @@ bits. Must be at least 3. · 3 unmodified lines
868</dd>462</dd>
869<dt><code>expBitsMax</code></dt>463<dt><code>expBitsMax</code></dt>
870<dd><p>Read-only integer. Return the maximum allowed exponent size in464<dd><p>Read-only integer. Return the maximum allowed exponent size in
871bits. Must be at least 11.465bits. Must be at least 15.
872</p>466</p>
873</dd>467</dd>
874<dt><code>RNDN</code></dt>468<dt><code>RNDN</code></dt>
@@ -891,11 +485,11 @@ bits. Must be at least 11. · 16 unmodified lines
891<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.485<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
892</p>486</p>
893</dd>487</dd>
894<dt><code>RNDNU</code></dt>488<dt><code>RNDA</code></dt>
895<dd><p>Read-only integer. Round to nearest, with ties to +Infinity rounding mode.489<dd><p>Read-only integer. Round away from zero rounding mode.
896</p>490</p>
897</dd>491</dd>
898<dt><code>RNDF<a name="DOCF8" href="#FOOT8"><sup>8</sup></a></code></dt>492<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
899<dd><p>Read-only integer. Faithful rounding mode. The result is493<dd><p>Read-only integer. Faithful rounding mode. The result is
900non-deterministically rounded to -Infinity or +Infinity. This rounding494non-deterministically rounded to -Infinity or +Infinity. This rounding
901mode usually gives a faster and deterministic running time for the495mode usually gives a faster and deterministic running time for the
@@ -939,102 +533,200 @@ assuming an IEEE 754 representation. · 37 unmodified lines
939</dd>533</dd>
940</dl>534</dl>
941 535
942<a name="Math-object-1"></a>536<a name="BigDecimal"></a>
943<h4 class="subsection">4.5.4 <code>Math</code> object</h4>537<h2 class="chapter">5 BigDecimal</h2>
944 538
945<p>The following properties are modified:539<p>This extension adds the <code>BigDecimal</code> primitive type. The
540<code>BigDecimal</code> type represents floating point numbers in base
54110. It is inspired from the proposal available at
542<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
543</p>
544<p>The <code>BigDecimal</code> floating point numbers are always normalized and
545finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
546<code>NaN</code>. By default, all the computations are done with infinite
547precision.
548</p>
549<a name="Operators-1"></a>
550<h3 class="section">5.1 Operators</h3>
551
552<p>The following builtin operators support BigDecimal:
946</p>553</p>
947<dl compact="compact">554<dl compact="compact">
948<dt><code>abs(x)</code></dt>555<dt><code>+</code></dt>
949<dd><p>Absolute value. If <code>x</code> is a BigFloat, its absolute value is556<dt><code>-</code></dt>
950returned as a BigFloat. No rounding is performed.557<dt><code>*</code></dt>
558<dd><p>Both operands must be BigDecimal. The result is computed with infinite
559precision.
560</p></dd>
561<dt><code>%</code></dt>
562<dd><p>Both operands must be BigDecimal. The result is computed with infinite
563precision. A range error is throws in case of division by zero.
951</p>564</p>
952</dd>565</dd>
953<dt><code>min(a, b)</code></dt>566<dt><code>/</code></dt>
954<dt><code>max(a, b)</code></dt>567<dd><p>Both operands must be BigDecimal. A range error is throws in case of
955<dd><p>The returned type is the same one as the minimum (resp. maximum)568division by zero or if the result cannot be represented with infinite
956value, so <code>BigFloat</code> values are accepted. When a <code>BigFloat</code>569precision (use <code>BigDecimal.div</code> to specify the rounding).
957is returned, no rounding is performed.570</p>
571</dd>
572<dt><code>**</code></dt>
573<dd><p>Both operands must be BigDecimal. The exponent must be a positive
574integer. The result is computed with infinite precision.
575</p>
576</dd>
577<dt><code>===</code></dt>
578<dd><p>When one of the operand is a BigDecimal, return true if both operands
579are a BigDecimal and if they are equal.
580</p>
581</dd>
582<dt><code>==</code></dt>
583<dt><code>!=</code></dt>
584<dt><code>&lt;=</code></dt>
585<dt><code>&gt;=</code></dt>
586<dt><code>&lt;</code></dt>
587<dt><code>&gt;</code></dt>
588<dd>
589<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
590converted to BigDecimal by using ToString(). Hence comparisons between
591Number and BigDecimal do not use the exact mathematical value of the
592Number value.
958</p>593</p>
959</dd>594</dd>
960</dl>595</dl>
961 596
962<a name="Math-mode"></a>597<a name="BigDecimal-literals"></a>
963<h2 class="chapter">5 Math mode</h2>598<h3 class="section">5.2 BigDecimal literals</h3>
964 599
965<a name="Introduction-4"></a>600<p>BigDecimal literals are decimal floating point numbers with a trailing
966<h3 class="section">5.1 Introduction</h3>601<code>m</code> suffix.
602</p>
603<a name="Builtin-Object-changes-1"></a>
604<h3 class="section">5.3 Builtin Object changes</h3>
967 605
968<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>606<a name="The-BigDecimal-function_002e"></a>
969directive. <code>&quot;use bigint&quot;</code> is implied in math mode. With this607<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
970mode, writing mathematical expressions is more intuitive, exact608
971results (e.g. fractions) can be computed for all operators and floating609<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
972point literals have the <code>BigFloat</code> type by default.610parameter is converted to a bigdecimal by using ToString(). Hence
611Number value are not converted to their exact numerical value as
612BigDecimal.
973</p>613</p>
974<p>It propagates the same way as the <em>strict mode</em>. In614<a name="Properties-of-the-BigDecimal-object"></a>
975this mode:615<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
616
617<dl compact="compact">
618<dt><code>add(a, b[, e])</code></dt>
619<dt><code>sub(a, b[, e])</code></dt>
620<dt><code>mul(a, b[, e])</code></dt>
621<dt><code>div(a, b[, e])</code></dt>
622<dt><code>mod(a, b[, e])</code></dt>
623<dt><code>sqrt(a, e)</code></dt>
624<dt><code>round(a, e)</code></dt>
625<dd><p>Perform the specified floating point operation and round the floating
626point result according to the rounding object <code>e</code>. If the
627rounding object is not present, the operation is executed with
628infinite precision.
976</p>629</p>
977<ul>630<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
978<li> The <code>^</code> operator is a similar to the power operator (<code>**</code>).631division by zero or if the result cannot be represented with infinite
632precision if no rounding object is present.
633</p>
634<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
635zero.
636</p>
637<p>The rounding object must contain the following properties:
638<code>roundingMode</code> is a string specifying the rounding mode
639(<code>&quot;floor&quot;</code>, <code>&quot;ceiling&quot;</code>, <code>&quot;down&quot;</code>, <code>&quot;up&quot;</code>,
640<code>&quot;half-even&quot;</code>, <code>&quot;half-up&quot;</code>). Either
641<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
642be present to specify respectively the number of significant digits
643(must be &gt;= 1) or the number of digits after the decimal point (must
644be &gt;= 0).
645</p>
646</dd>
647</dl>
979 648
980</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>.649<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
650<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
981 651
982</li><li> The logical xor operator is still available with the <code>^^</code> operator.652<dl compact="compact">
653<dt><code>valueOf()</code></dt>
654<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
655</p>
656</dd>
657<dt><code>toString()</code></dt>
658<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
659</p>
660</dd>
661<dt><code>toPrecision(p, rnd_mode = &quot;half-up&quot;)</code></dt>
662<dt><code>toFixed(p, rnd_mode = &quot;half-up&quot;)</code></dt>
663<dt><code>toExponential(p, rnd_mode = &quot;half-up&quot;)</code></dt>
664<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
665precision <code>p</code>. There is no limit on the accepted precision
666<code>p</code>. The rounding mode can be optionally
667specified. <code>toPrecision</code> outputs either in decimal fixed notation
668or in decimal exponential notation with a <code>p</code> digits of
669precision. <code>toExponential</code> outputs in decimal exponential
670notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
671outputs in decimal notation with <code>p</code> digits after the decimal
672point.
673</p>
674</dd>
675</dl>
983 676
984</li><li> The division operator invokes <code>BigInt[Symbol.operatorDiv]</code> in case both operands are integers.677<a name="Math-mode"></a>
678<h2 class="chapter">6 Math mode</h2>
985 679
986</li><li> The power operator invokes <code>BigInt[Symbol.operatorPow]</code> in case both operands are integers and the exponent is strictly negative.680<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
681directive. It propagates the same way as the <em>strict mode</em>. It is
682designed so that arbitrarily large integers and floating point numbers
683are available by default. In order to minimize the number of changes
684in the Javascript semantics, integers are represented either as Number
685or BigInt depending on their magnitude. Floating point numbers are
686always represented as BigFloat.
687</p>
688<p>The following changes are made to the Javascript semantics:
689</p>
690<ul>
691<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === &quot;bigfloat&quot;</code>.
987 692
988</li><li> The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.693</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === &quot;number &quot;</code>, <code>typeof 1n === &quot;number&quot;</code> but <code>typeof 9007199254740992 === &quot;bigint&quot; </code>.
989 694
990</li><li> Floating point literals are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied).695</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.
991 696
992</li></ul>697</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.
993 698
994<a name="Builtin-Object-changes-3"></a>699</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
995<h3 class="section">5.2 Builtin Object changes</h3>
996 700
997<a name="Symbol-constructor-1"></a>701</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>.
998<h4 class="subsection">5.2.1 <code>Symbol</code> constructor</h4>
999 702
1000<p>The following global symbol is added for the operator overloading:703</li><li> The logical xor operator is still available with the <code>^^</code> operator.
1001</p><dl compact="compact">
1002<dt><code>operatorMathMod</code></dt>
1003</dl>
1004 704
1005<a name="Remaining-issues"></a>705</li><li> The integer division operator can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
1006<h3 class="section">5.3 Remaining issues</h3>
1007 706
1008<ol>707</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>.
1009<li> A new floating point literal suffix could be added for <code>Number</code> literals.
1010 708
1011</li></ol>709</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
710
711</li></ul>
1012 712
1013<div class="footnote">713<div class="footnote">
1014<hr>714<hr>
1015<h4 class="footnotes-heading">Footnotes</h4>715<h4 class="footnotes-heading">Footnotes</h4>
1016 716
1017<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>717<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
1018<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
1019<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
1020<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
1021<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
1022<p>Could be extended to 53 bits without changing the principle.</p>
1023<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
1024<p>The unsigned right right operator could be removed in bigint mode.</p>
1025<h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
1026<p>The718<p>The
1027rationale is that the rounding mode changes must always be719rationale is that the rounding mode changes must always be
1028explicit.</p>720explicit.</p>
1029<h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>721<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
1030<p>The rationale is to avoid side effects for the built-in722<p>The rationale is to avoid side effects for the built-in
1031operators.</p>723operators.</p>
1032<h3><a name="FOOT7" href="#DOCF7">(7)</a></h3>724<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
1033<p>Base 10 floating point literals cannot usually be725<p>Base 10 floating point literals cannot usually be
1034exactly represented as base 2 floating point number. In order to726exactly represented as base 2 floating point number. In order to
1035ensure that the literal is represented accurately with the current727ensure that the literal is represented accurately with the current
1036precision, it must be evaluated at runtime.</p>728precision, it must be evaluated at runtime.</p>
1037<h3><a name="FOOT8" href="#DOCF8">(8)</a></h3>729<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
1038<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>730<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
1039</div>731</div>
1040<hr>732<hr>
doc/jsbignum.pdf+0−0

Binary file not shown.

doc/jsbignum.texi+179−422
@@ -10,12 +10,12 @@ · 9 unmodified lines
10@sp 710@sp 7
11@center @titlefont{Javascript Bignum Extensions}11@center @titlefont{Javascript Bignum Extensions}
12@sp 312@sp 3
13@center Version 2018-06-1613@center Version 2020-01-11
14@sp 314@sp 3
15@center Author: Fabrice Bellard15@center Author: Fabrice Bellard
16@end titlepage16@end titlepage
17 17
18@setfilename spec.info18@setfilename jsbignum.info
19@settitle Javascript Bignum Extensions19@settitle Javascript Bignum Extensions
20 20
21@contents21@contents
@@ -27,348 +27,52 @@ language while being 100% backward compatible: · 5 unmodified lines
27 27
28@itemize28@itemize
29 29
30@item Overloading of the standard operators30@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
31to support new types such as complex numbers, fractions or matrices.
32
33@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/}}).
34 31
35@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.32@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
36 33
37@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.34@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
35@url{https://github.com/littledan/proposal-bigdecimal}.
36
37@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
38remainder. @code{^} is an alias to the power operator
39(@code{**}). @code{^^} is used as the exclusive or operator.
38 40
39@end itemize41@end itemize
40 42
41The extensions are independent from each other except the @code{math}43The extensions are independent from each other except the @code{math}
42mode which relies on the bigint mode and the operator overloading.44mode which relies on BigFloat and operator overloading.
43 45
44@chapter Operator overloading46@chapter Operator overloading
45 47
46@section Introduction48Operator overloading is inspired from the proposal available at
47 49@url{https://github.com/tc39/proposal-operator-overloading/}. It
48If the operands of an operator have at least one object type, a custom50implements the same dispatch logic but finds the operator sets by
49operator method is searched before doing the legacy Javascript51looking at the @code{Symbol.operatorSet} property in the objects. The
50@code{ToNumber} conversion.52changes were done in order to simplify the implementation.
51
52For unary operators, the custom function is looked up in the object
53and has the following name:
54
55@table @code
56@item unary +
57@code{Symbol.operatorPlus}
58
59@item unary -
60@code{Symbol.operatorNeg}
61
62@item ++
63@code{Symbol.operatorInc}
64
65@item --
66@code{Symbol.operatorDec}
67
68@item ~
69@code{Symbol.operatorNot}
70
71@end table
72
73For binary operators:
74
75@itemize
76
77@item
78If both operands have the same constructor function, then the operator
79is looked up in the constructor.
80
81@item
82Otherwise, the property @code{Symbol.operatorOrder} is looked up in both
83constructors and converted to @code{Int32}. The operator is then
84looked in the constructor with the larger @code{Symbol.operatorOrder}
85value. A @code{TypeError} is raised if both constructors have the same
86@code{Symbol.operatorOrder} value.
87
88@end itemize
89
90The operator is looked up with the following name:
91
92@table @code
93@item +
94@code{Symbol.operatorAdd}
95
96@item -
97@code{Symbol.operatorSub}
98
99@item *
100@code{Symbol.operatorMul}
101
102@item /
103@code{Symbol.operatorDiv}
104
105@item %
106@code{Symbol.operatorMod}
107
108@item % (math mode)
109@code{Symbol.operatorMathMod}
110
111@item **
112@code{Symbol.operatorPow}
113
114@item |
115@code{Symbol.operatorOr}
116
117@item ^
118@code{Symbol.operatorXor}
119
120@item &
121@code{Symbol.operatorAnd}
122
123@item <<
124@code{Symbol.operatorShl}
125
126@item >>
127@code{Symbol.operatorShr}
128
129@item <
130@code{Symbol.operatorCmpLT}
131
132@item >
133@code{Symbol.operatorCmpLT}, operands swapped
134
135@item <=
136@code{Symbol.operatorCmpLE}
137
138@item >=
139@code{Symbol.operatorCmpLE}, operands swapped
140
141@item ==, !=
142@code{Symbol.operatorCmpEQ}
143
144@end table
145
146The return value of @code{Symbol.operatorCmpLT}, @code{Symbol.operatorCmpLE} and
147@code{Symbol.operatorCmpEQ} is converted to @code{Boolean}.
148
149@section Builtin Object changes
150
151@subsection @code{Symbol} constructor
152
153The following global symbols are added for the operator overloading:
154@table @code
155@item operatorOrder
156@item operatorAdd
157@item operatorSub
158@item operatorMul
159@item operatorDiv
160@item operatorMod
161@item operatorPow
162@item operatorShl
163@item operatorShr
164@item operatorAnd
165@item operatorOr
166@item operatorXor
167@item operatorCmpLT
168@item operatorCmpLE
169@item operatorCmpEQ
170@item operatorPlus
171@item operatorNeg
172@item operatorNot
173@item operatorInc
174@item operatorDec
175@end table
176
177
178@chapter The BigInt Mode
179 53
180@section Introduction54More precisely, the following modifications were made:
181
182The bigint mode is enabled with the @code{"use bigint"} directive. It
183propagates the same way as the strict mode. In bigint mode, all
184integers are considered as @code{bigint} (arbitrarily large integer,
185similar to the TC39 BigInt
186proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}})
187instead of @code{number} (floating point number). In order to be able
188to exchange data between standard and bigint modes, numbers are
189internally represented as 3 different types:
190 55
191@itemize56@itemize
192 57
193@item Small integer (SmallInt): 32 bit integer@footnote{Could be extended to 53 bits without changing the principle.}.58@item @code{with operators from} is not supported. Operator overloading is always enabled.
194
195@item Big integer (BigInt): arbitrarily large integer.
196
197@item Floating point number (Float).
198
199@end itemize
200
201In standard mode, the semantics of each operation is modified so that
202when it returns a @code{number}, it is either of SmallInt or
203Float. But the difference between SmallInt and Float is not observable
204in standard mode.
205
206In bigint mode, each operation behaves differently whether its
207operands are integer or float. The difference between SmallInt and
208BigInt is not observable (i.e. they are both integers).
209
210The following table summarizes the observable types:
211
212@multitable @columnfractions .3 .3 .3
213@headitem Internal type @tab Observable type@* (standard mode) @tab Observable type@* (bigint mode)
214@item SmallInt @tab number @tab bigint
215@item BigInt @tab bigint @tab bigint
216@item Float @tab number @tab number
217@end multitable
218
219@section Changes that introduce incompatibilities with Javascript
220
221@subsection Standard mode
222
223There is no incompatibility with Javascript.
224
225@subsection Bigint mode
226
227The following changes are visible:
228
229@itemize
230
231@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.
232
233@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.
234
235@item Binary bitwise operators do not truncate to 32 bits i.e. @code{0x800000000 | 1 === 0x800000001} while it gives @code{1} in standard mode.
236 59
237@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.}.60@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.
238 61
239@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.62@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.
240 63
241@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).64@item @code{[]} cannot be overloaded.
242 65
243@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.66@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
244 67
245@item If the TC39 BigInt proposal is supported, there is no observable difference between integers and @code{bigint}s.
246
247@end itemize
248
249@section Operators
250
251@subsection Arithmetic operators
252
253The operands are converted to number values as in normal
254Javascript. Then the general case is that an Integer is returned if
255both operands are Integer. Otherwise, a float is returned.
256
257The @code{+} operator also accepts strings as input and behaves like
258standard Javascript in this case.
259
260The binary operator @code{%} returns the truncated remainder of the
261division. When the result is an Integer type, a dividend of zero yields a
262RangeError exception.
263
264The binary operator @code{%} in math mode returns the Euclidian
265remainder of the division i.e. it is always positive.
266
267The binary operator @code{/} returns a float.
268
269The binary operator @code{/} in math mode returns a float if one of
270the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is
271invoked.
272
273The returned type of @code{a ** b} is Float if @math{a} or @math{b}
274are Float. If @math{a} and @math{b} are integers:
275@itemize
276@item @math{b < 0} returns a Float in bigint mode. In math mode, @code{BigInt[Symbol.operatorPow]} is invoked.
277
278@item @math{b >= 0} returns an integer.
279@end itemize68@end itemize
280 69
281The unary @code{-} and unary @code{+} return the same type as their70@chapter BigInt extensions
282operand. They performs no floating point rounding when the result is a
283float.
284
285The unary operators @code{++} and @code{--} return the same type as
286their operand.
287
288In standard mode:
289
290If the operator returns an Integer and that the result fits a
291SmallInt, it is converted to SmallInt. Otherwise, the Integer is
292converted to a Float.
293
294In bigint mode:
295
296If the operator returns an Integer and that the result fits a
297SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
298
299@subsection Logical operators
300
301In standard mode:
302
303The operands have their standard behavior. If the result fits a
304SmallInt it is converted to a SmallInt. Otherwise it is a Float.
305
306In bigint mode:
307
308The operands are converted to integer values. The floating point
309values are converted to integer by rounding them to zero.
310
311The logical operators are defined assuming the integers are
312represented in two complement notation.
313
314For @code{<<} and @code{<<}, the shift can be positive or negative. So
315@code{a << b} is defined as @math{\lfloor a/2^{-b} \rfloor} and
316@code{a >> b} is defined as @math{\lfloor a/2^{b} \rfloor}.
317
318The operator @code{>>>} is supported for backward compatibility and
319behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}.
320 71
321If the result fits a SmallInt it is converted to a SmallInt. Otherwise72A few properties are added to the BigInt object:
322it is a BigInt.
323
324@subsection Relational operators
325
326The relational operators <, <=, >, >=, ==, != work as expected with
327integers and floating point numbers (e.g. @code{1.0 == 1} is true).
328
329The strict equality operators === and !== have the usual Javascript
330semantics. In particular, different types never equal, so @code{1.0
331=== 1} is false.
332
333@section Number literals
334
335Number literals in bigint mode have a slightly different behavior than
336in standard Javascript:
337
338@enumerate
339
340@item
341A number literal without a decimal point or an exponent is considered
342as an Integer. Otherwise it is a Float.
343
344@item
345Hexadecimal, octal or binary floating point literals are accepted with
346a decimal point or an exponent. The exponent is specified with the
347@code{p} letter assuming a base 2. The same convention is used by
348C99. Example: @code{0x1p3} is the same as @code{8.0}.
349
350@end enumerate
351
352@section Builtin Object changes
353
354@subsection @code{BigInt} function
355
356The @code{BigInt} function cannot be invoked as a constructor. When
357invoked as a function, it converts its first parameter to an
358integer. When a floating point number is given as parameter, it is
359truncated to an integer with infinite precision.
360
361@code{BigInt} properties:
362 73
363@table @code74@table @code
364 75
365@item asIntN(bits, a)
366Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}}
367otherwise @math{b-2^{bits}}.
368
369@item asUintN(bits, a)
370Return @math{a \pmod{2^{bits}}}.
371
372@item tdiv(a, b)76@item tdiv(a, b)
373Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError77Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
374exception.78exception.
@@ -410,58 +114,7 @@ Return the number of trailing zeros in the two's complement binary representatio · 35 unmodified lines
410 114
411@end table115@end table
412 116
413@subsection @code{BigInt.prototype}117@chapter BigFloat
414
415It is a normal object.
416
417@subsection @code{Number} constructor
418
419The number constructor returns its argument rounded to a Float using
420the global floating point environment. In bigint mode, the Number
421constructor returns a Float. In standard mode, it returns a SmallInt
422if the value fits it, otherwise a Float.
423
424@subsection @code{Number.prototype}
425
426The following properties are modified:
427
428@table @code
429@item toString(radix)
430
431In bigint mode, integers are converted to the specified radix with
432infinite precision.
433
434@item toPrecision(p)
435@item toFixed(p)
436@item toExponential(p)
437
438In bigint mode, integers are accepted and converted to string with
439infinite precision.
440
441@item parseInt(string, radix)
442
443In bigint mode, an integer is returned and the conversion is done with
444infinite precision.
445
446@end table
447
448@subsection @code{Math} object
449
450The following properties are modified:
451
452@table @code
453@item abs(x)
454Absolute value. Return an integer if @code{x} is an Integer. Otherwise
455return a Float. No rounding is performed.
456
457@item min(a, b)
458@item max(a, b)
459No rounding is performed. The returned type is the same one as the
460minimum (resp. maximum) value.
461
462@end table
463
464@chapter Arbitrarily large floating point numbers
465 118
466@section Introduction119@section Introduction
467 120
@@ -590,6 +243,9 @@ point number @code{a} according to the floating point environment · 122 unmodified lines
590@item trunc(x)243@item trunc(x)
591Round to an integer. No additional rounding is performed.244Round to an integer. No additional rounding is performed.
592 245
246@item abs(x)
247Return the absolute value of x. No additional rounding is performed.
248
593@item fmod(x, y[, e])249@item fmod(x, y[, e])
594@item remainder(x, y[, e])250@item remainder(x, y[, e])
595Floating point remainder. The quotient is truncated to zero (fmod) or251Floating point remainder. The quotient is truncated to zero (fmod) or
@@ -620,6 +276,9 @@ number. @code{e} is an optional floating point environment. · 24 unmodified lines
620The following properties are modified:276The following properties are modified:
621 277
622@table @code278@table @code
279@item valueOf()
280Return the bigfloat primitive value corresponding to @code{this}.
281
623@item toString(radix)282@item toString(radix)
624 283
625For floating point numbers:284For floating point numbers:
@@ -636,13 +295,16 @@ the global precision and round to nearest gives the same number. · 10 unmodified lines
636 295
637@end itemize296@end itemize
638 297
639@item toPrecision(p[, rnd_mode])298The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
640@item toFixed(p[, rnd_mode])29916 with a binary exponent and @code{@@} for the other bases.
641@item toExponential(p[, rnd_mode])300
301@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
302@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
303@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
642Same semantics as the corresponding @code{Number} functions with304Same semantics as the corresponding @code{Number} functions with
643BigFloats. There is no limit on the accepted precision @code{p}. The305BigFloats. There is no limit on the accepted precision @code{p}. The
644rounding mode can be optionally specified. It is set by default to306rounding mode and radix can be optionally specified. The radix must be
645@code{BigFloatEnv.RNDNA}.307between 2 and 36.
646 308
647@end table309@end table
648 310
@@ -679,13 +341,13 @@ subnormal flags is set to @code{false}. If @code{rndMode} is · 30 unmodified lines
679 341
680@item prec342@item prec
681Getter. Return the precision in bits of the global floating point343Getter. Return the precision in bits of the global floating point
682environment. The initial value is @code{53}.344environment. The initial value is @code{113}.
683 345
684@item expBits346@item expBits
685Getter. Return the exponent size in bits of the global floating point347Getter. Return the exponent size in bits of the global floating point
686environment assuming an IEEE 754 representation. If @code{expBits <348environment assuming an IEEE 754 representation. If @code{expBits <
687expBitsMax}, then subnormal numbers are supported. The initial value349expBitsMax}, then subnormal numbers are supported. The initial value
688is @code{11}.350is @code{15}.
689 351
690@item setPrec(f, p[, e])352@item setPrec(f, p[, e])
691Set the precision of the global floating point environment to @code{p}353Set 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 · 1 unmodified line
693@code{f}. Then the Float precision and exponent size are reset to355@code{f}. Then the Float precision and exponent size are reset to
694their precious value and the return value of @code{f} is returned (or356their precious value and the return value of @code{f} is returned (or
695an exception is raised if @code{f} raised an exception). If @code{e}357an exception is raised if @code{f} raised an exception). If @code{e}
696is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. @code{p}358is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
697must be >= 53 and @code{e} must be >= 11 so that the global precision
698is at least equivalent to the IEEE 754 64 bit doubles.
699 359
700@item precMin360@item precMin
701Read-only integer. Return the minimum allowed precision. Must be at least 2.361Read-only integer. Return the minimum allowed precision. Must be at least 2.
702 362
703@item precMax363@item precMax
704Read-only integer. Return the maximum allowed precision. Must be at least 53.364Read-only integer. Return the maximum allowed precision. Must be at least 113.
705 365
706@item expBitsMin366@item expBitsMin
707Read-only integer. Return the minimum allowed exponent size in367Read-only integer. Return the minimum allowed exponent size in
@@ -709,7 +369,7 @@ bits. Must be at least 3. · 1 unmodified line
709 369
710@item expBitsMax370@item expBitsMax
711Read-only integer. Return the maximum allowed exponent size in371Read-only integer. Return the maximum allowed exponent size in
712bits. Must be at least 11.372bits. Must be at least 15.
713 373
714@item RNDN374@item RNDN
715Read-only integer. Round to nearest, with ties to even rounding mode.375Read-only integer. Round to nearest, with ties to even rounding mode.
@@ -726,8 +386,8 @@ Read-only integer. Round to +Infinity rounding mode. · 10 unmodified lines
726@item RNDNA386@item RNDNA
727Read-only integer. Round to nearest, with ties away from zero rounding mode.387Read-only integer. Round to nearest, with ties away from zero rounding mode.
728 388
729@item RNDNU389@item RNDA
730Read-only integer. Round to nearest, with ties to +Infinity rounding mode.390Read-only integer. Round away from zero rounding mode.
731 391
732@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}392@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
733Read-only integer. Faithful rounding mode. The result is393Read-only integer. Faithful rounding mode. The result is
@@ -767,69 +427,166 @@ Getter and setter (Boolean). Status flags. · 33 unmodified lines
767 427
768@end table428@end table
769 429
770@subsection @code{Math} object430@chapter BigDecimal
771 431
772The following properties are modified:432This extension adds the @code{BigDecimal} primitive type. The
433@code{BigDecimal} type represents floating point numbers in base
43410. It is inspired from the proposal available at
435@url{https://github.com/littledan/proposal-bigdecimal}.
436
437The @code{BigDecimal} floating point numbers are always normalized and
438finite. There is no concept of @code{-0}, @code{Infinity} or
439@code{NaN}. By default, all the computations are done with infinite
440precision.
441
442@section Operators
443
444The following builtin operators support BigDecimal:
773 445
774@table @code446@table @code
775@item abs(x)
776Absolute value. If @code{x} is a BigFloat, its absolute value is
777returned as a BigFloat. No rounding is performed.
778 447
779@item min(a, b)448@item +
780@item max(a, b)449@item -
781The returned type is the same one as the minimum (resp. maximum)450@item *
782value, so @code{BigFloat} values are accepted. When a @code{BigFloat}451Both operands must be BigDecimal. The result is computed with infinite
783is returned, no rounding is performed.452precision.
453@item %
454Both operands must be BigDecimal. The result is computed with infinite
455precision. A range error is throws in case of division by zero.
784 456
785@end table457@item /
458Both operands must be BigDecimal. A range error is throws in case of
459division by zero or if the result cannot be represented with infinite
460precision (use @code{BigDecimal.div} to specify the rounding).
786 461
787@chapter Math mode462@item **
463Both operands must be BigDecimal. The exponent must be a positive
464integer. The result is computed with infinite precision.
788 465
789@section Introduction466@item ===
467When one of the operand is a BigDecimal, return true if both operands
468are a BigDecimal and if they are equal.
790 469
791A new @emph{math mode} is enabled with the @code{"use math"}470@item ==
792directive. @code{"use bigint"} is implied in math mode. With this471@item !=
793mode, writing mathematical expressions is more intuitive, exact472@item <=
794results (e.g. fractions) can be computed for all operators and floating473@item >=
795point literals have the @code{BigFloat} type by default.474@item <
475@item >
796 476
797It propagates the same way as the @emph{strict mode}. In477Numerical comparison. When one of the operand is not a BigDecimal, it is
798this mode:478converted to BigDecimal by using ToString(). Hence comparisons between
479Number and BigDecimal do not use the exact mathematical value of the
480Number value.
799 481
800@itemize482@end table
801 483
802@item The @code{^} operator is a similar to the power operator (@code{**}).484@section BigDecimal literals
803 485
804@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.486BigDecimal literals are decimal floating point numbers with a trailing
487@code{m} suffix.
805 488
806@item The logical xor operator is still available with the @code{^^} operator.489@section Builtin Object changes
807 490
808@item The division operator invokes @code{BigInt[Symbol.operatorDiv]} in case both operands are integers.491@subsection The @code{BigDecimal} function.
809 492
810@item The power operator invokes @code{BigInt[Symbol.operatorPow]} in case both operands are integers and the exponent is strictly negative.493It returns @code{0m} if no parameter is provided. Otherwise the first
494parameter is converted to a bigdecimal by using ToString(). Hence
495Number value are not converted to their exact numerical value as
496BigDecimal.
811 497
812@item The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.498@subsection Properties of the @code{BigDecimal} object
813 499
814@item Floating point literals are @code{BigFloat} by default (i.e. a @code{l} suffix is implied).500@table @code
815 501
816@end itemize502@item add(a, b[, e])
503@item sub(a, b[, e])
504@item mul(a, b[, e])
505@item div(a, b[, e])
506@item mod(a, b[, e])
507@item sqrt(a, e)
508@item round(a, e)
509Perform the specified floating point operation and round the floating
510point result according to the rounding object @code{e}. If the
511rounding object is not present, the operation is executed with
512infinite precision.
817 513
818@section Builtin Object changes514For @code{div}, a @code{RangeError} exception is thrown in case of
515division by zero or if the result cannot be represented with infinite
516precision if no rounding object is present.
517
518For @code{sqrt}, a range error is thrown if @code{a} is less than
519zero.
520
521The rounding object must contain the following properties:
522@code{roundingMode} is a string specifying the rounding mode
523(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
524@code{"half-even"}, @code{"half-up"}). Either
525@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
526be present to specify respectively the number of significant digits
527(must be >= 1) or the number of digits after the decimal point (must
528be >= 0).
819 529
820@subsection @code{Symbol} constructor530@end table
531
532@subsection Properties of the @code{BigDecimal.prototype} object
821 533
822The following global symbol is added for the operator overloading:
823@table @code534@table @code
824@item operatorMathMod535@item valueOf()
536Return the bigdecimal primitive value corresponding to @code{this}.
537
538@item toString()
539Convert @code{this} to a string with infinite precision in base 10.
540
541@item toPrecision(p, rnd_mode = "half-up")
542@item toFixed(p, rnd_mode = "half-up")
543@item toExponential(p, rnd_mode = "half-up")
544Convert the BigDecimal @code{this} to string with the specified
545precision @code{p}. There is no limit on the accepted precision
546@code{p}. The rounding mode can be optionally
547specified. @code{toPrecision} outputs either in decimal fixed notation
548or in decimal exponential notation with a @code{p} digits of
549precision. @code{toExponential} outputs in decimal exponential
550notation with @code{p} digits after the decimal point. @code{toFixed}
551outputs in decimal notation with @code{p} digits after the decimal
552point.
553
825@end table554@end table
826 555
827@section Remaining issues556@chapter Math mode
828 557
829@enumerate558A new @emph{math mode} is enabled with the @code{"use math"}
559directive. It propagates the same way as the @emph{strict mode}. It is
560designed so that arbitrarily large integers and floating point numbers
561are available by default. In order to minimize the number of changes
562in the Javascript semantics, integers are represented either as Number
563or BigInt depending on their magnitude. Floating point numbers are
564always represented as BigFloat.
565
566The following changes are made to the Javascript semantics:
830 567
831@item A new floating point literal suffix could be added for @code{Number} literals.568@itemize
832 569
833@end enumerate570@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"}.
571
572@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" }.
573
574@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.
575
576@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.
577
578@item The @code{^} operator is an alias to the power operator (@code{**}).
579
580@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
581
582@item The logical xor operator is still available with the @code{^^} operator.
583
584@item The integer division operator can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
585
586@item The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
587
588@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
589
590@end itemize
834 591
835@bye592@bye
doc/quickjs.html+12−3
@@ -1,7 +1,8 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2<html>2<html>
3<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->3<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
4<head>4<head>
5<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5<title>QuickJS Javascript Engine</title>6<title>QuickJS Javascript Engine</title>
6 7
7<meta name="description" content="QuickJS Javascript Engine">8<meta name="description" content="QuickJS Javascript Engine">
@@ -9,7 +10,6 @@ · 1 unmodified line
9<meta name="resource-type" content="document">10<meta name="resource-type" content="document">
10<meta name="distribution" content="global">11<meta name="distribution" content="global">
11<meta name="Generator" content="makeinfo">12<meta name="Generator" content="makeinfo">
12<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
13<link href="#SEC_Contents" rel="contents" title="Table of Contents">13<link href="#SEC_Contents" rel="contents" title="Table of Contents">
14<style type="text/css">14<style type="text/css">
15<!--15<!--
@@ -206,7 +206,7 @@ Javascript files and/or expressions as arguments to execute them: · 190 unmodified lines
206<a name="qjs-interpreter"></a>206<a name="qjs-interpreter"></a>
207<h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>207<h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>
208 208
209<pre class="verbatim">usage: qjs [options] [files]209<pre class="verbatim">usage: qjs [options] [file [args]]
210</pre>210</pre>
211<p>Options are:211<p>Options are:
212</p><dl compact="compact">212</p><dl compact="compact">
@@ -241,6 +241,11 @@ source is <code>import</code>. · 28 unmodified lines
241the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.241the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.
242</p>242</p>
243</dd>243</dd>
244<dt><code>-I file</code></dt>
245<dt><code>--include file</code></dt>
246<dd><p>Include an additional file.
247</p>
248</dd>
244</dl>249</dl>
245 250
246<p>Advanced options are:251<p>Advanced options are:
@@ -767,6 +772,10 @@ pathname of <code>path</code> and <code>err</code> the error code. · 520 unmodified lines
767and <code>err</code> the error code.772and <code>err</code> the error code.
768</p>773</p>
769</dd>774</dd>
775<dt><code>chdir(path)</code></dt>
776<dd><p>Change the current directory. Return the error code.
777</p>
778</dd>
770<dt><code>mkdir(path, mode = 0o777)</code></dt>779<dt><code>mkdir(path, mode = 0o777)</code></dt>
771<dd><p>Create a directory at <code>path</code>. Return the error code.780<dd><p>Create a directory at <code>path</code>. Return the error code.
772</p>781</p>
doc/quickjs.pdf+0−0

Binary file not shown.

doc/quickjs.texi+8−1
@@ -92,7 +92,7 @@ generates a @code{hello} executable with no external dependency. · 91 unmodified lines
92@subsection @code{qjs} interpreter92@subsection @code{qjs} interpreter
93 93
94@verbatim94@verbatim
95usage: qjs [options] [files]95usage: qjs [options] [file [args]]
96@end verbatim96@end verbatim
97 97
98Options are:98Options are:
@@ -122,6 +122,10 @@ Load as ES6 script (default=autodetect). · 23 unmodified lines
122Enable the bignum extensions: BigDecimal object, BigFloat object and122Enable the bignum extensions: BigDecimal object, BigFloat object and
123the @code{"use bigint"} and @code{"use math"} directives.123the @code{"use bigint"} and @code{"use math"} directives.
124 124
125@item -I file
126@item --include file
127Include an additional file.
128
125@end table129@end table
126 130
127Advanced options are:131Advanced options are:
@@ -576,6 +580,9 @@ pathname of @code{path} and @code{err} the error code. · 448 unmodified lines
576Return @code{[str, err]} where @code{str} is the current working directory580Return @code{[str, err]} where @code{str} is the current working directory
577and @code{err} the error code.581and @code{err} the error code.
578 582
583@item chdir(path)
584Change the current directory. Return the error code.
585
579@item mkdir(path, mode = 0o777)586@item mkdir(path, mode = 0o777)
580Create a directory at @code{path}. Return the error code.587Create a directory at @code{path}. Return the error code.
581 588
examples/pi_bigdecimal.js+8−10
@@ -6,10 +6,10 @@ · 5 unmodified lines
6 6
7/* compute PI with a precision of 'prec' digits */7/* compute PI with a precision of 'prec' digits */
8function calc_pi(prec) {8function calc_pi(prec) {
9 const CHUD_A = 13591409d;9 const CHUD_A = 13591409m;
10 const CHUD_B = 545140134d;10 const CHUD_B = 545140134m;
11 const CHUD_C = 640320d;11 const CHUD_C = 640320m;
12 const CHUD_C3 = 10939058860032000d; /* C^3/24 */12 const CHUD_C3 = 10939058860032000m; /* C^3/24 */
13 const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */13 const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
14 14
15 /* return [P, Q, G] */15 /* return [P, Q, G] */
@@ -17,7 +17,7 @@ function calc_pi(prec) { · 1 unmodified line
17 var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;17 var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
18 if (a == (b - 1n)) {18 if (a == (b - 1n)) {
19 b1 = BigDecimal(b);19 b1 = BigDecimal(b);
20 G = (2d * b1 - 1d) * (6d * b1 - 1d) * (6d * b1 - 5d);20 G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
21 P = G * (CHUD_B * b1 + CHUD_A);21 P = G * (CHUD_B * b1 + CHUD_A);
22 if (b & 1n)22 if (b & 1n)
23 P = -P;23 P = -P;
@@ -32,7 +32,7 @@ function calc_pi(prec) { · 8 unmodified lines
32 if (need_G)32 if (need_G)
33 G = G1 * G2;33 G = G1 * G2;
34 else34 else
35 G = 0d;35 G = 0m;
36 }36 }
37 return [P, Q, G];37 return [P, Q, G];
38 }38 }
@@ -44,7 +44,7 @@ function calc_pi(prec) { · 5 unmodified lines
44 Q = BigDecimal.div(Q, (P + Q * CHUD_A),44 Q = BigDecimal.div(Q, (P + Q * CHUD_A),
45 { roundingMode: "half-even",45 { roundingMode: "half-even",
46 maximumSignificantDigits: prec });46 maximumSignificantDigits: prec });
47 G = (CHUD_C / 12d) * BigDecimal.sqrt(CHUD_C,47 G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
48 { roundingMode: "half-even",48 { roundingMode: "half-even",
49 maximumSignificantDigits: prec });49 maximumSignificantDigits: prec });
50 return Q * G;50 return Q * G;
@@ -64,7 +64,5 @@ function calc_pi(prec) { · 13 unmodified lines
64 /* we add more digits to reduce the probability of bad rounding for64 /* we add more digits to reduce the probability of bad rounding for
65 the last digits */65 the last digits */
66 r = calc_pi(n_digits + 20);66 r = calc_pi(n_digits + 20);
67 r = BigDecimal.round(r, { roundingMode: "down",67 print(r.toFixed(n_digits, "down"));
68 maximumFractionDigits: n_digits })
69 print(r);
70})();68})();
libbf.c+677−439
@@ -86,7 +86,6 @@ static no_inline int fft_mul(bf_context_t *s, · 85 unmodified lines
86static void fft_clear_cache(bf_context_t *s);86static void fft_clear_cache(bf_context_t *s);
87#endif87#endif
88#ifdef USE_BF_DEC88#ifdef USE_BF_DEC
89static void mp_pow_init(void);
90static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);89static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);
91#endif90#endif
92 91
@@ -154,6 +153,17 @@ static inline limb_t smod(slimb_t a, slimb_t b) · 61 unmodified lines
154 return a;153 return a;
155}154}
156 155
156/* signed addition with saturation */
157static inline slimb_t sat_add(slimb_t a, slimb_t b)
158{
159 slimb_t r;
160 r = a + b;
161 /* overflow ? */
162 if (((a ^ r) & (b ^ r)) < 0)
163 r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);
164 return r;
165}
166
157#define malloc(s) malloc_is_forbidden(s)167#define malloc(s) malloc_is_forbidden(s)
158#define free(p) free_is_forbidden(p)168#define free(p) free_is_forbidden(p)
159#define realloc(p, s) realloc_is_forbidden(p, s)169#define realloc(p, s) realloc_is_forbidden(p, s)
@@ -164,9 +174,6 @@ void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, · 4 unmodified lines
164 memset(s, 0, sizeof(*s));174 memset(s, 0, sizeof(*s));
165 s->realloc_func = realloc_func;175 s->realloc_func = realloc_func;
166 s->realloc_opaque = realloc_opaque;176 s->realloc_opaque = realloc_opaque;
167#ifdef USE_BF_DEC
168 mp_pow_init();
169#endif
170}177}
171 178
172void bf_context_end(bf_context_t *s)179void bf_context_end(bf_context_t *s)
@@ -422,18 +429,13 @@ static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, · 249 unmodified lines
422 if (r->sign == (rnd_mode == BF_RNDD))429 if (r->sign == (rnd_mode == BF_RNDD))
423 add_one = inexact;430 add_one = inexact;
424 break;431 break;
432 case BF_RNDA:
433 add_one = inexact;
434 break;
425 case BF_RNDNA:435 case BF_RNDNA:
426 case BF_RNDF:436 case BF_RNDF:
427 add_one = bit1;437 add_one = bit1;
428 break;438 break;
429 case BF_RNDNU:
430 if (bit1) {
431 if (r->sign)
432 add_one = bit0;
433 else
434 add_one = 1;
435 }
436 break;
437 default:439 default:
438 abort();440 abort();
439 }441 }
@@ -452,7 +454,7 @@ static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) · 12 unmodified lines
452 if (prec == BF_PREC_INF ||454 if (prec == BF_PREC_INF ||
453 rnd_mode == BF_RNDN ||455 rnd_mode == BF_RNDN ||
454 rnd_mode == BF_RNDNA ||456 rnd_mode == BF_RNDNA ||
455 rnd_mode == BF_RNDNU ||457 rnd_mode == BF_RNDA ||
456 (rnd_mode == BF_RNDD && sign == 1) ||458 (rnd_mode == BF_RNDD && sign == 1) ||
457 (rnd_mode == BF_RNDU && sign == 0)) {459 (rnd_mode == BF_RNDU && sign == 0)) {
458 bf_set_inf(r, sign);460 bf_set_inf(r, sign);
@@ -476,12 +478,14 @@ static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) · 17 unmodified lines
476 478
477/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is479/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
478 assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be480 assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be
479 infinite (BF_PREC_INF). Can fail with BF_ST_MEM_ERROR in case of481 infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result
482 is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of
480 overflow not returning infinity. */483 overflow not returning infinity. */
481static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l)484static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,
485 int ret)
482{486{
483 limb_t v, a;487 limb_t v, a;
484 int shift, add_one, ret, rnd_mode;488 int shift, add_one, rnd_mode;
485 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;489 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
486 490
487 /* e_min and e_max are computed to match the IEEE 754 conventions */491 /* e_min and e_max are computed to match the IEEE 754 conventions */
@@ -506,7 +510,6 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 18 unmodified lines
506 510
507 /* round to prec bits */511 /* round to prec bits */
508 rnd_mode = flags & BF_RND_MASK;512 rnd_mode = flags & BF_RND_MASK;
509 ret = 0;
510 add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);513 add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);
511 514
512 if (prec <= 0) {515 if (prec <= 0) {
@@ -615,7 +618,7 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags) · 102 unmodified lines
615 }618 }
616 r->expn -= shift;619 r->expn -= shift;
617 }620 }
618 ret = __bf_round(r, prec1, flags, l);621 ret = __bf_round(r, prec1, flags, l, 0);
619 }622 }
620 // bf_print_str("r_final", r);623 // bf_print_str("r_final", r);
621 return ret;624 return ret;
@@ -638,8 +641,7 @@ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) · 16 unmodified lines
638 }641 }
639 if (a->expn == BF_EXP_ZERO)642 if (a->expn == BF_EXP_ZERO)
640 return FALSE;643 return FALSE;
641 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||644 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
642 rnd_mode == BF_RNDNU);
643 if (k < (prec + 2))645 if (k < (prec + 2))
644 return FALSE;646 return FALSE;
645 bit_pos = a->len * LIMB_BITS - 1 - prec;647 bit_pos = a->len * LIMB_BITS - 1 - prec;
@@ -666,7 +668,7 @@ int bf_round(bf_t *r, limb_t prec, bf_flags_t flags) · 20 unmodified lines
666{668{
667 if (r->len == 0)669 if (r->len == 0)
668 return 0;670 return 0;
669 return __bf_round(r, prec, flags, r->len);671 return __bf_round(r, prec, flags, r->len, 0);
670}672}
671 673
672/* for debugging */674/* for debugging */
@@ -780,51 +782,26 @@ int bf_cmp_full(const bf_t *a, const bf_t *b) · 107 unmodified lines
780 return res;782 return res;
781}783}
782 784
783#define BF_CMP_EQ 1785/* Standard floating point comparison: return 2 if one of the operands
784#define BF_CMP_LT 2786 is NaN (unordered) or -1, 0, 1 depending on the ordering assuming
785#define BF_CMP_LE 3787 -0 == +0 */
786 788int bf_cmp(const bf_t *a, const bf_t *b)
787static int bf_cmp(const bf_t *a, const bf_t *b, int op)
788{789{
789 BOOL is_both_zero;
790 int res;790 int res;
791 791
792 if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN)792 if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
793 return 0;793 res = 2;
794 if (a->sign != b->sign) {794 } else if (a->sign != b->sign) {
795 is_both_zero = (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO);795 if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)
796 if (is_both_zero) {796 res = 0;
797 return op & BF_CMP_EQ;797 else
798 } else if (op & BF_CMP_LT) {798 res = 1 - 2 * a->sign;
799 return a->sign;
800 } else {
801 return FALSE;
802 }
803 } else {799 } else {
804 res = bf_cmpu(a, b);800 res = bf_cmpu(a, b);
805 if (res == 0) {801 if (a->sign)
806 return op & BF_CMP_EQ;802 res = -res;
807 } else if (op & BF_CMP_LT) {
808 return (res < 0) ^ a->sign;
809 } else {
810 return FALSE;
811 }
812 }803 }
813}804 return res;
814
815int bf_cmp_eq(const bf_t *a, const bf_t *b)
816{
817 return bf_cmp(a, b, BF_CMP_EQ);
818}
819
820int bf_cmp_le(const bf_t *a, const bf_t *b)
821{
822 return bf_cmp(a, b, BF_CMP_LE);
823}
824
825int bf_cmp_lt(const bf_t *a, const bf_t *b)
826{
827 return bf_cmp(a, b, BF_CMP_LT);
828}805}
829 806
830/* Compute the number of bits 'n' matching the pattern:807/* Compute the number of bits 'n' matching the pattern:
@@ -1631,11 +1608,11 @@ int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags) · 800 unmodified lines
1631 slimb_t e_max;1608 slimb_t e_max;
1632 if (r->len == 0)1609 if (r->len == 0)
1633 return 0;1610 return 0;
1634 e_max = ((limb_t)1 << BF_EXP_BITS_MAX) - 1;1611 e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;
1635 e = bf_max(e, -e_max);1612 e = bf_max(e, -e_max);
1636 e = bf_min(e, e_max);1613 e = bf_min(e, e_max);
1637 r->expn += e;1614 r->expn += e;
1638 return __bf_round(r, prec, flags, r->len);1615 return __bf_round(r, prec, flags, r->len, 0);
1639}1616}
1640 1617
1641/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,1618/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,
@@ -1777,8 +1754,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 135 unmodified lines
1777 }1754 }
1778 1755
1779 q_sign = a->sign ^ b->sign;1756 q_sign = a->sign ^ b->sign;
1780 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||1757 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
1781 rnd_mode == BF_RNDNU);
1782 switch(rnd_mode) {1758 switch(rnd_mode) {
1783 default:1759 default:
1784 case BF_RNDZ:1760 case BF_RNDZ:
@@ -1792,12 +1768,12 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 7 unmodified lines
1792 case BF_RNDU:1768 case BF_RNDU:
1793 is_ceil = q_sign ^ 1;1769 is_ceil = q_sign ^ 1;
1794 break;1770 break;
1771 case BF_RNDA:
1772 is_ceil = TRUE;
1773 break;
1795 case BF_DIVREM_EUCLIDIAN:1774 case BF_DIVREM_EUCLIDIAN:
1796 is_ceil = a->sign;1775 is_ceil = a->sign;
1797 break;1776 break;
1798 case BF_RNDNU:
1799 /* XXX: unsupported yet */
1800 abort();
1801 }1777 }
1802 1778
1803 a1->expn = a->expn;1779 a1->expn = a->expn;
@@ -1845,26 +1821,14 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 41 unmodified lines
1845 return BF_ST_MEM_ERROR;1821 return BF_ST_MEM_ERROR;
1846}1822}
1847 1823
1848int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,1824int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1849 bf_flags_t flags)1825 bf_flags_t flags, int rnd_mode)
1850{1826{
1851 bf_t q_s, *q = &q_s;1827 bf_t q_s, *q = &q_s;
1852 int ret;1828 int ret;
1853 1829
1854 bf_init(r->ctx, q);1830 bf_init(r->ctx, q);
1855 ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDZ);1831 ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
1856 bf_delete(q);
1857 return ret;
1858}
1859
1860int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1861 bf_flags_t flags)
1862{
1863 bf_t q_s, *q = &q_s;
1864 int ret;
1865
1866 bf_init(r->ctx, q);
1867 ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDN);
1868 bf_delete(q);1832 bf_delete(q);
1869 return ret;1833 return ret;
1870}1834}
@@ -1879,13 +1843,13 @@ static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags) · 8 unmodified lines
1879}1843}
1880 1844
1881int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,1845int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1882 bf_flags_t flags)1846 bf_flags_t flags, int rnd_mode)
1883{1847{
1884 bf_t q_s, *q = &q_s;1848 bf_t q_s, *q = &q_s;
1885 int ret;1849 int ret;
1886 1850
1887 bf_init(r->ctx, q);1851 bf_init(r->ctx, q);
1888 ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDN);1852 ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
1889 bf_get_limb(pq, q, BF_GET_INT_MOD);1853 bf_get_limb(pq, q, BF_GET_INT_MOD);
1890 bf_delete(q);1854 bf_delete(q);
1891 return ret;1855 return ret;
@@ -2791,14 +2755,14 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 899 unmodified lines
2791 /* XXX: correct overflow/underflow handling */2755 /* XXX: correct overflow/underflow handling */
2792 /* XXX: rigorous error analysis needed */2756 /* XXX: rigorous error analysis needed */
2793 extra_bits = ceil_log2(e) * 2 + 1;2757 extra_bits = ceil_log2(e) * 2 + 1;
2794 ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN);2758 ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
2795 overflow = !bf_is_finite(B);2759 overflow = !bf_is_finite(B);
2796 /* XXX: if bf_pow_ui_ui returns an exact result, can stop2760 /* XXX: if bf_pow_ui_ui returns an exact result, can stop
2797 after the next operation */2761 after the next operation */
2798 if (expn_sign)2762 if (expn_sign)
2799 ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN);2763 ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
2800 else2764 else
2801 ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN);2765 ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
2802 if (ret & BF_ST_MEM_ERROR)2766 if (ret & BF_ST_MEM_ERROR)
2803 break;2767 break;
2804 if ((ret & BF_ST_INEXACT) &&2768 if ((ret & BF_ST_INEXACT) &&
@@ -2807,6 +2771,8 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 2 unmodified lines
2807 /* and more precision and retry */2771 /* and more precision and retry */
2808 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);2772 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
2809 } else {2773 } else {
2774 /* XXX: need to use __bf_round() to pass the inexact
2775 flag for the subnormal case */
2810 ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);2776 ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);
2811 break;2777 break;
2812 }2778 }
@@ -3062,7 +3028,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, · 249 unmodified lines
3062 c = to_digit(*p);3028 c = to_digit(*p);
3063 if (c >= 10)3029 if (c >= 10)
3064 break;3030 break;
3065 if (unlikely(expn > ((EXP_MAX - 2 - 9) / 10))) {3031 if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {
3066 /* exponent overflow */3032 /* exponent overflow */
3067 if (exp_is_neg) {3033 if (exp_is_neg) {
3068 bf_set_zero(r, is_neg);3034 bf_set_zero(r, is_neg);
@@ -3501,11 +3467,14 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, · 432 unmodified lines
3501 prec = prec0 + ziv_extra_bits;3467 prec = prec0 + ziv_extra_bits;
3502 /* XXX: rigorous error analysis needed */3468 /* XXX: rigorous error analysis needed */
3503 extra_bits = ceil_log2(e) * 2 + 1;3469 extra_bits = ceil_log2(e) * 2 + 1;
3504 ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits, BF_RNDN);3470 ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,
3471 BF_RNDN | BF_FLAG_EXT_EXP);
3505 if (!e_sign)3472 if (!e_sign)
3506 ret |= bf_mul(r, r, a, prec + extra_bits, BF_RNDN);3473 ret |= bf_mul(r, r, a, prec + extra_bits,
3474 BF_RNDN | BF_FLAG_EXT_EXP);
3507 else3475 else
3508 ret |= bf_div(r, a, r, prec + extra_bits, BF_RNDN);3476 ret |= bf_div(r, a, r, prec + extra_bits,
3477 BF_RNDN | BF_FLAG_EXT_EXP);
3509 if (ret & BF_ST_MEM_ERROR)3478 if (ret & BF_ST_MEM_ERROR)
3510 return BF_ST_MEM_ERROR;3479 return BF_ST_MEM_ERROR;
3511 /* if the result is not exact, check that it can be safely3480 /* if the result is not exact, check that it can be safely
@@ -3605,7 +3574,15 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 93 unmodified lines
3605 pos = a->len;3574 pos = a->len;
3606 pos_incr = 1;3575 pos_incr = 1;
3607 first_buf_pos = 0;3576 first_buf_pos = 0;
3608 } else if ((radix & (radix - 1)) != 0) {3577 } else if ((radix & (radix - 1)) == 0) {
3578 a = (bf_t *)a1;
3579 radix_bits = ceil_log2(radix);
3580 digits_per_limb = LIMB_BITS / radix_bits;
3581 pos_incr = digits_per_limb * radix_bits;
3582 /* digits are aligned relative to the radix point */
3583 pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);
3584 first_buf_pos = 0;
3585 } else {
3609 limb_t n, radixl;3586 limb_t n, radixl;
3610 3587
3611 digits_per_limb = digits_per_limb_table[radix - 2];3588 digits_per_limb = digits_per_limb_table[radix - 2];
@@ -3619,13 +3596,6 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 7 unmodified lines
3619 pos = n;3596 pos = n;
3620 pos_incr = 1;3597 pos_incr = 1;
3621 first_buf_pos = pos * digits_per_limb - n_digits;3598 first_buf_pos = pos * digits_per_limb - n_digits;
3622 } else {
3623 a = (bf_t *)a1;
3624 radix_bits = ceil_log2(radix);
3625 digits_per_limb = LIMB_BITS / radix_bits;
3626 pos_incr = digits_per_limb * radix_bits;
3627 pos = a->len * LIMB_BITS - a->expn + n_digits * radix_bits;
3628 first_buf_pos = 0;
3629 }3599 }
3630 buf_pos = digits_per_limb;3600 buf_pos = digits_per_limb;
3631 i = 0;3601 i = 0;
@@ -3668,12 +3638,13 @@ static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size) · 36 unmodified lines
3668static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,3638static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,
3669 limb_t prec, bf_flags_t flags, BOOL is_dec)3639 limb_t prec, bf_flags_t flags, BOOL is_dec)
3670{3640{
3641 bf_context_t *ctx = a2->ctx;
3671 DynBuf s_s, *s = &s_s;3642 DynBuf s_s, *s = &s_s;
3672 int radix_bits;3643 int radix_bits;
3673 3644
3674 // bf_print_str("ftoa", a2);3645 // bf_print_str("ftoa", a2);
3675 // printf("radix=%d\n", radix);3646 // printf("radix=%d\n", radix);
3676 dbuf_init2(s, a2->ctx, bf_dbuf_realloc);3647 dbuf_init2(s, ctx, bf_dbuf_realloc);
3677 if (a2->expn == BF_EXP_NAN) {3648 if (a2->expn == BF_EXP_NAN) {
3678 dbuf_putstr(s, "NaN");3649 dbuf_putstr(s, "NaN");
3679 } else {3650 } else {
@@ -3687,77 +3658,160 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 7 unmodified lines
3687 } else {3658 } else {
3688 int fmt, ret;3659 int fmt, ret;
3689 slimb_t n_digits, n, i, n_max, n1;3660 slimb_t n_digits, n, i, n_max, n1;
3690 bf_t a1_s, *a1;3661 bf_t a1_s, *a1 = &a1_s;
3691 bf_t a_s, *a = &a_s;3662
3692
3693 /* make a positive number */
3694 a->tab = a2->tab;
3695 a->len = a2->len;
3696 a->expn = a2->expn;
3697 a->sign = 0;
3698
3699 if ((radix & (radix - 1)) != 0)3663 if ((radix & (radix - 1)) != 0)
3700 radix_bits = 0;3664 radix_bits = 0;
3701 else3665 else
3702 radix_bits = ceil_log2(radix);3666 radix_bits = ceil_log2(radix);
3703 3667
3704 fmt = flags & BF_FTOA_FORMAT_MASK;3668 fmt = flags & BF_FTOA_FORMAT_MASK;
3705 a1 = &a1_s;3669 bf_init(ctx, a1);
3706 bf_init(a2->ctx, a1);
3707 if (fmt == BF_FTOA_FORMAT_FRAC) {3670 if (fmt == BF_FTOA_FORMAT_FRAC) {
3708 size_t pos, start;3671 if (is_dec || radix_bits != 0) {
3709 assert(!is_dec);3672 if (bf_set(a1, a2))
3710 /* one more digit for the rounding */3673 goto fail1;
3711 n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);3674#ifdef USE_BF_DEC
3712 n_digits = n + prec;3675 if (is_dec) {
3713 n1 = n;3676 if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
3714 if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,3677 goto fail1;
3715 flags & BF_RND_MASK, TRUE))3678 n = a1->expn;
3716 goto fail1;3679 } else
3717 start = s->size;3680#endif
3718 output_digits(s, a1, radix, n_digits, n, is_dec);3681 {
3719 /* remove leading zeros because we allocated one more digit */3682 if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
3720 pos = start;3683 goto fail1;
3721 while ((pos + 1) < s->size && s->buf[pos] == '0' &&3684 n = ceil_div(a1->expn, radix_bits);
3722 s->buf[pos + 1] != '.')3685 }
3723 pos++;3686 if (flags & BF_FTOA_ADD_PREFIX) {
3724 if (pos > start) {3687 if (radix == 16)
3725 memmove(s->buf + start, s->buf + pos, s->size - pos);3688 dbuf_putstr(s, "0x");
3726 s->size -= (pos - start);3689 else if (radix == 8)
3690 dbuf_putstr(s, "0o");
3691 else if (radix == 2)
3692 dbuf_putstr(s, "0b");
3693 }
3694 if (a1->expn == BF_EXP_ZERO) {
3695 dbuf_putstr(s, "0");
3696 if (prec > 0) {
3697 dbuf_putstr(s, ".");
3698 for(i = 0; i < prec; i++) {
3699 dbuf_putc(s, '0');
3700 }
3701 }
3702 } else {
3703 n_digits = prec + n;
3704 if (n <= 0) {
3705 /* 0.x */
3706 dbuf_putstr(s, "0.");
3707 for(i = 0; i < -n; i++) {
3708 dbuf_putc(s, '0');
3709 }
3710 if (n_digits > 0) {
3711 output_digits(s, a1, radix, n_digits, n_digits, is_dec);
3712 }
3713 } else {
3714 output_digits(s, a1, radix, n_digits, n, is_dec);
3715 }
3716 }
3717 } else {
3718 size_t pos, start;
3719 bf_t a_s, *a = &a_s;
3720
3721 /* make a positive number */
3722 a->tab = a2->tab;
3723 a->len = a2->len;
3724 a->expn = a2->expn;
3725 a->sign = 0;
3726
3727 /* one more digit for the rounding */
3728 n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);
3729 n_digits = n + prec;
3730 n1 = n;
3731 if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,
3732 flags & BF_RND_MASK, TRUE))
3733 goto fail1;
3734 start = s->size;
3735 output_digits(s, a1, radix, n_digits, n, is_dec);
3736 /* remove leading zeros because we allocated one more digit */
3737 pos = start;
3738 while ((pos + 1) < s->size && s->buf[pos] == '0' &&
3739 s->buf[pos + 1] != '.')
3740 pos++;
3741 if (pos > start) {
3742 memmove(s->buf + start, s->buf + pos, s->size - pos);
3743 s->size -= (pos - start);
3744 }
3727 }3745 }
3728 } else {3746 } else {
3729#ifdef USE_BF_DEC3747#ifdef USE_BF_DEC
3730 if (is_dec) {3748 if (is_dec) {
3749 if (bf_set(a1, a2))
3750 goto fail1;
3731 if (fmt == BF_FTOA_FORMAT_FIXED) {3751 if (fmt == BF_FTOA_FORMAT_FIXED) {
3732 n_digits = prec;3752 n_digits = prec;
3733 n_max = n_digits;3753 n_max = n_digits;
3754 if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
3755 goto fail1;
3734 } else {3756 } else {
3735 /* prec is ignored */3757 /* prec is ignored */
3736 prec = n_digits = a->len * LIMB_DIGITS;3758 prec = n_digits = a1->len * LIMB_DIGITS;
3737 /* remove trailing zero digits */3759 /* remove the trailing zero digits */
3738 while (n_digits > 1 &&3760 while (n_digits > 1 &&
3739 get_digit(a->tab, a->len, prec - n_digits) == 0) {3761 get_digit(a1->tab, a1->len, prec - n_digits) == 0) {
3740 n_digits--;3762 n_digits--;
3741 }3763 }
3742 n_max = n_digits + 4;3764 n_max = n_digits + 4;
3743 }3765 }
3744 bf_init(a2->ctx, a1);
3745 bf_set(a1, a);
3746 n = a1->expn;3766 n = a1->expn;
3747 } else3767 } else
3748#endif3768#endif
3749 {3769 if (radix_bits != 0) {
3770 if (bf_set(a1, a2))
3771 goto fail1;
3772 if (fmt == BF_FTOA_FORMAT_FIXED) {
3773 slimb_t prec_bits;
3774 n_digits = prec;
3775 n_max = n_digits;
3776 /* align to the radix point */
3777 prec_bits = prec * radix_bits -
3778 smod(-a1->expn, radix_bits);
3779 if (bf_round(a1, prec_bits,
3780 (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
3781 goto fail1;
3782 } else {
3783 limb_t digit_mask;
3784 slimb_t pos;
3785 /* position of the digit before the most
3786 significant digit in bits */
3787 pos = a1->len * LIMB_BITS +
3788 smod(-a1->expn, radix_bits);
3789 n_digits = ceil_div(pos, radix_bits);
3790 /* remove the trailing zero digits */
3791 digit_mask = ((limb_t)1 << radix_bits) - 1;
3792 while (n_digits > 1 &&
3793 (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {
3794 n_digits--;
3795 }
3796 n_max = n_digits + 4;
3797 }
3798 n = ceil_div(a1->expn, radix_bits);
3799 } else {
3800 bf_t a_s, *a = &a_s;
3801
3802 /* make a positive number */
3803 a->tab = a2->tab;
3804 a->len = a2->len;
3805 a->expn = a2->expn;
3806 a->sign = 0;
3807
3750 if (fmt == BF_FTOA_FORMAT_FIXED) {3808 if (fmt == BF_FTOA_FORMAT_FIXED) {
3751 n_digits = prec;3809 n_digits = prec;
3752 n_max = n_digits;3810 n_max = n_digits;
3753 } else {3811 } else {
3754 slimb_t n_digits_max, n_digits_min;3812 slimb_t n_digits_max, n_digits_min;
3755 3813
3756 if (prec == BF_PREC_INF) {3814 assert(prec != BF_PREC_INF);
3757 assert(radix_bits != 0);
3758 /* XXX: could use the exact number of bits */
3759 prec = a->len * LIMB_BITS;
3760 }
3761 n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);3815 n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);
3762 /* max number of digits for non exponential3816 /* max number of digits for non exponential
3763 notation. The rational is to have the same rule3817 notation. The rational is to have the same rule
@@ -3771,7 +3825,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 7 unmodified lines
3771 /* XXX: inefficient */3825 /* XXX: inefficient */
3772 n_digits_max = n_digits;3826 n_digits_max = n_digits;
3773 n_digits_min = 1;3827 n_digits_min = 1;
3774 bf_init(a2->ctx, b);3828 bf_init(ctx, b);
3775 while (n_digits_min < n_digits_max) {3829 while (n_digits_min < n_digits_max) {
3776 n_digits = (n_digits_min + n_digits_max) / 2;3830 n_digits = (n_digits_min + n_digits_max) / 2;
3777 if (bf_convert_to_radix(a1, &n, a, radix, n_digits,3831 if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
@@ -3869,7 +3923,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 91 unmodified lines
3869 *plen = s->size - 1;3923 *plen = s->size - 1;
3870 return (char *)s->buf;3924 return (char *)s->buf;
3871 fail:3925 fail:
3872 bf_free(a2->ctx, s->buf);3926 bf_free(ctx, s->buf);
3873 if (plen)3927 if (plen)
3874 *plen = 0;3928 *plen = 0;
3875 return NULL;3929 return NULL;
@@ -4035,7 +4089,7 @@ static void bf_const_pi_internal(bf_t *Q, limb_t prec) · 159 unmodified lines
4035 4089
4036static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,4090static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,
4037 BFConstCache *c,4091 BFConstCache *c,
4038 void (*func)(bf_t *res, limb_t prec))4092 void (*func)(bf_t *res, limb_t prec), int sign)
4039{4093{
4040 limb_t ziv_extra_bits, prec1;4094 limb_t ziv_extra_bits, prec1;
4041 4095
@@ -4051,6 +4105,7 @@ static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags, · 9 unmodified lines
4051 prec1 = c->prec;4105 prec1 = c->prec;
4052 }4106 }
4053 bf_set(T, &c->val);4107 bf_set(T, &c->val);
4108 T->sign = sign;
4054 if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {4109 if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {
4055 /* and more precision and retry */4110 /* and more precision and retry */
4056 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);4111 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
@@ -4070,13 +4125,20 @@ static void bf_const_free(BFConstCache *c) · 13 unmodified lines
4070int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)4125int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)
4071{4126{
4072 bf_context_t *s = T->ctx;4127 bf_context_t *s = T->ctx;
4073 return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal);4128 return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);
4074}4129}
4075 4130
4076int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)4131/* return rounded pi * (1 - 2 * sign) */
4132static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)
4077{4133{
4078 bf_context_t *s = T->ctx;4134 bf_context_t *s = T->ctx;
4079 return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal);4135 return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,
4136 sign);
4137}
4138
4139int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)
4140{
4141 return bf_const_pi_signed(T, 0, prec, flags);
4080}4142}
4081 4143
4082void bf_clear_cache(bf_context_t *s)4144void bf_clear_cache(bf_context_t *s)
@@ -4126,9 +4188,29 @@ static int bf_ziv_rounding(bf_t *r, const bf_t *a, · 43 unmodified lines
4126 break;4188 break;
4127 }4189 }
4128 ziv_extra_bits = ziv_extra_bits * 2;4190 ziv_extra_bits = ziv_extra_bits * 2;
4191 // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);
4129 }4192 }
4130 }4193 }
4131 return bf_round(r, prec, flags) | ret;4194 if (r->len == 0)
4195 return ret;
4196 else
4197 return __bf_round(r, prec, flags, r->len, ret);
4198}
4199
4200/* add (1 - 2*e_sign) * 2^e */
4201static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,
4202 limb_t prec, int flags)
4203{
4204 bf_t T_s, *T = &T_s;
4205 int ret;
4206 /* small argument case: result = 1 + epsilon * sign(x) */
4207 bf_init(a->ctx, T);
4208 bf_set_ui(T, 1);
4209 T->sign = e_sign;
4210 T->expn += e;
4211 ret = bf_add(r, r, T, prec, flags);
4212 bf_delete(T);
4213 return ret;
4132}4214}
4133 4215
4134/* Compute the exponential using faithful rounding at precision 'prec'.4216/* Compute the exponential using faithful rounding at precision 'prec'.
@@ -4193,18 +4275,70 @@ static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 58 unmodified lines
4193 4275
4194 /* undo the range reduction */4276 /* undo the range reduction */
4195 for(i = 0; i < K; i++) {4277 for(i = 0; i < K; i++) {
4196 bf_mul(r, r, r, prec1, BF_RNDN);4278 bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
4197 }4279 }
4198 4280
4199 /* undo the argument reduction */4281 /* undo the argument reduction */
4200 bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ);4282 bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);
4201 4283
4202 return BF_ST_INEXACT;4284 return BF_ST_INEXACT;
4203}4285}
4204 4286
4287/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */
4288static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,
4289 const bf_t *a_low, const bf_t *a_high,
4290 limb_t prec, bf_flags_t flags)
4291{
4292 bf_t T_s, *T = &T_s;
4293 bf_t log2_s, *log2 = &log2_s;
4294 slimb_t e_min, e_max;
4295
4296 if (a_high->expn <= 0)
4297 return 0;
4298
4299 e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
4300 e_min = -e_max + 3;
4301 if (flags & BF_FLAG_SUBNORMAL)
4302 e_min -= (prec - 1);
4303
4304 bf_init(s, T);
4305 bf_init(s, log2);
4306 bf_const_log2(log2, LIMB_BITS, BF_RNDU);
4307 bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
4308 /* a_low > e_max * log(2) implies exp(a) > e_max */
4309 if (bf_cmp_lt(T, a_low) > 0) {
4310 /* overflow */
4311 bf_delete(T);
4312 bf_delete(log2);
4313 return bf_set_overflow(r, 0, prec, flags);
4314 }
4315 /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */
4316 bf_const_log2(log2, LIMB_BITS, BF_RNDD);
4317 bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);
4318 if (bf_cmp_lt(a_high, T)) {
4319 int rnd_mode = flags & BF_RND_MASK;
4320
4321 /* underflow */
4322 bf_delete(T);
4323 bf_delete(log2);
4324 if (rnd_mode == BF_RNDU) {
4325 /* set the smallest value */
4326 bf_set_ui(r, 1);
4327 r->expn = e_min;
4328 } else {
4329 bf_set_zero(r, 0);
4330 }
4331 return BF_ST_UNDERFLOW | BF_ST_INEXACT;
4332 }
4333 bf_delete(log2);
4334 bf_delete(T);
4335 return 0;
4336}
4337
4205int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)4338int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
4206{4339{
4207 bf_context_t *s = r->ctx;4340 bf_context_t *s = r->ctx;
4341 int ret;
4208 assert(r != a);4342 assert(r != a);
4209 if (a->len == 0) {4343 if (a->len == 0) {
4210 if (a->expn == BF_EXP_NAN) {4344 if (a->expn == BF_EXP_NAN) {
@@ -4220,48 +4354,15 @@ int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 9 unmodified lines
4220 return 0;4354 return 0;
4221 }4355 }
4222 4356
4223 /* crude overflow and underflow tests */4357 ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);
4224 if (a->expn > 0) {4358 if (ret)
4225 bf_t T_s, *T = &T_s;4359 return ret;
4226 bf_t log2_s, *log2 = &log2_s;4360 if (a->expn < 0 && (-a->expn) >= (prec + 2)) {
4227 slimb_t e_min, e_max;4361 /* small argument case: result = 1 + epsilon * sign(x) */
4228 e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);4362 bf_set_ui(r, 1);
4229 e_min = -e_max + 3;4363 return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);
4230 if (flags & BF_FLAG_SUBNORMAL)
4231 e_min -= (prec - 1);
4232
4233 bf_init(s, T);
4234 bf_init(s, log2);
4235 bf_const_log2(log2, LIMB_BITS, BF_RNDU);
4236 bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
4237 /* a > e_max * log(2) implies exp(a) > e_max */
4238 if (bf_cmp_lt(T, a) > 0) {
4239 /* overflow */
4240 bf_delete(T);
4241 bf_delete(log2);
4242 return bf_set_overflow(r, 0, prec, flags);
4243 }
4244 /* a < e_min * log(2) implies exp(a) < e_min */
4245 bf_mul_si(T, log2, e_min, LIMB_BITS, BF_RNDD);
4246 if (bf_cmp_lt(a, T)) {
4247 int rnd_mode = flags & BF_RND_MASK;
4248
4249 /* underflow */
4250 bf_delete(T);
4251 bf_delete(log2);
4252 if (rnd_mode == BF_RNDU) {
4253 /* set the smallest value */
4254 bf_set_ui(r, 1);
4255 r->expn = e_min;
4256 } else {
4257 bf_set_zero(r, 0);
4258 }
4259 return BF_ST_UNDERFLOW | BF_ST_INEXACT;
4260 }
4261 bf_delete(log2);
4262 bf_delete(T);
4263 }4364 }
4264 4365
4265 return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);4366 return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);
4266}4367}
4267 4368
@@ -4404,7 +4505,6 @@ int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 136 unmodified lines
4404}4505}
4405 4506
4406/* x and y finite and x > 0 */4507/* x and y finite and x > 0 */
4407/* XXX: overflow/underflow handling */
4408static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)4508static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
4409{4509{
4410 bf_context_t *s = r->ctx;4510 bf_context_t *s = r->ctx;
@@ -4415,15 +4515,17 @@ static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque) · 4 unmodified lines
4415 bf_init(s, T);4515 bf_init(s, T);
4416 /* XXX: proof for the added precision */4516 /* XXX: proof for the added precision */
4417 prec1 = prec + 32;4517 prec1 = prec + 32;
4418 bf_log(T, x, prec1, BF_RNDF);4518 bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
4419 bf_mul(T, T, y, prec1, BF_RNDF);4519 bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
4420 bf_exp(r, T, prec1, BF_RNDF);4520 if (bf_is_nan(T))
4521 bf_set_nan(r);
4522 else
4523 bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */
4421 bf_delete(T);4524 bf_delete(T);
4422 return BF_ST_INEXACT;4525 return BF_ST_INEXACT;
4423}4526}
4424 4527
4425/* x and y finite, x > 0, y integer and y fits on one limb */4528/* x and y finite, x > 0, y integer and y fits on one limb */
4426/* XXX: overflow/underflow handling */
4427static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)4529static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
4428{4530{
4429 bf_context_t *s = r->ctx;4531 bf_context_t *s = r->ctx;
@@ -4438,11 +4540,11 @@ static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) · 8 unmodified lines
4438 y1 = -y1;4540 y1 = -y1;
4439 /* XXX: proof for the added precision */4541 /* XXX: proof for the added precision */
4440 prec1 = prec + ceil_log2(y1) * 2 + 8;4542 prec1 = prec + ceil_log2(y1) * 2 + 8;
4441 ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN);4543 ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
4442 if (y->sign) {4544 if (y->sign) {
4443 bf_init(s, T);4545 bf_init(s, T);
4444 bf_set_ui(T, 1);4546 bf_set_ui(T, 1);
4445 ret |= bf_div(r, T, r, prec1, BF_RNDN);4547 ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
4446 bf_delete(T);4548 bf_delete(T);
4447 }4549 }
4448 return ret;4550 return ret;
@@ -4508,7 +4610,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) · 59 unmodified lines
4508 int cmp_x_abs_1;4610 int cmp_x_abs_1;
4509 bf_set_ui(r, 1);4611 bf_set_ui(r, 1);
4510 cmp_x_abs_1 = bf_cmpu(x, r);4612 cmp_x_abs_1 = bf_cmpu(x, r);
4511 if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUICKS) &&4613 if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&
4512 (y->expn >= BF_EXP_INF)) {4614 (y->expn >= BF_EXP_INF)) {
4513 bf_set_nan(r);4615 bf_set_nan(r);
4514 } else if (cmp_x_abs_1 == 0 &&4616 } else if (cmp_x_abs_1 == 0 &&
@@ -4565,70 +4667,95 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) · 50 unmodified lines
4565 if (bf_cmp_eq(T, r)) {4667 if (bf_cmp_eq(T, r)) {
4566 /* abs(x) = 1: nothing more to do */4668 /* abs(x) = 1: nothing more to do */
4567 ret = 0;4669 ret = 0;
4568 } else if (y_is_int) {4670 } else {
4569 slimb_t T_bits, e;4671 /* check the overflow/underflow cases */
4570 int_pow:4672 {
4571 T_bits = T->expn - bf_get_exp_min(T);4673 bf_t al_s, *al = &al_s;
4572 if (T_bits == 1) {4674 bf_t ah_s, *ah = &ah_s;
4573 /* pow(2^b, y) = 2^(b*y) */4675 limb_t precl = LIMB_BITS;
4574 bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);4676
4575 bf_get_limb(&e, T, 0);4677 bf_init(s, al);
4576 bf_set_ui(r, 1);4678 bf_init(s, ah);
4577 ret = bf_mul_2exp(r, e, prec, flags);4679 /* compute bounds of log(abs(x)) * y with a low precision */
4578 } else if (prec == BF_PREC_INF) {4680 /* XXX: compute bf_log() once */
4579 slimb_t y1;4681 /* XXX: add a fast test before this slow test */
4580 /* specific case for infinite precision (integer case) */4682 bf_log(al, T, precl, BF_RNDD);
4581 bf_get_limb(&y1, y, 0);4683 bf_log(ah, T, precl, BF_RNDU);
4582 assert(!y->sign);4684 bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);
4583 /* x must be an integer, so abs(x) >= 2 */4685 bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);
4584 if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {4686 ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);
4585 bf_delete(T);4687 bf_delete(al);
4586 return bf_set_overflow(r, 0, BF_PREC_INF, flags);4688 bf_delete(ah);
4587 }4689 if (ret)
4588 ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);4690 goto done;
4589 } else {4691 }
4590 if (y->expn <= 31) {4692
4591 /* small enough power: use exponentiation in all cases */4693 if (y_is_int) {
4592 } else if (y->sign) {4694 slimb_t T_bits, e;
4593 /* cannot be exact */4695 int_pow:
4594 goto general_case;4696 T_bits = T->expn - bf_get_exp_min(T);
4697 if (T_bits == 1) {
4698 /* pow(2^b, y) = 2^(b*y) */
4699 bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);
4700 bf_get_limb(&e, T, 0);
4701 bf_set_ui(r, 1);
4702 ret = bf_mul_2exp(r, e, prec, flags);
4703 } else if (prec == BF_PREC_INF) {
4704 slimb_t y1;
4705 /* specific case for infinite precision (integer case) */
4706 bf_get_limb(&y1, y, 0);
4707 assert(!y->sign);
4708 /* x must be an integer, so abs(x) >= 2 */
4709 if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {
4710 bf_delete(T);
4711 return bf_set_overflow(r, 0, BF_PREC_INF, flags);
4712 }
4713 ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);
4595 } else {4714 } else {
4596 if (rnd_mode == BF_RNDF)4715 if (y->expn <= 31) {
4597 goto general_case; /* no need to track exact results */4716 /* small enough power: use exponentiation in all cases */
4598 /* see if the result has a chance to be exact:4717 } else if (y->sign) {
4599 if x=a*2^b (a odd), x^y=a^y*2^(b*y)4718 /* cannot be exact */
4600 x^y needs a precision of at least floor_log2(a)*y bits
4601 */
4602 bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
4603 bf_get_limb(&e, r, 0);
4604 if (prec < e)
4605 goto general_case;4719 goto general_case;
4720 } else {
4721 if (rnd_mode == BF_RNDF)
4722 goto general_case; /* no need to track exact results */
4723 /* see if the result has a chance to be exact:
4724 if x=a*2^b (a odd), x^y=a^y*2^(b*y)
4725 x^y needs a precision of at least floor_log2(a)*y bits
4726 */
4727 bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
4728 bf_get_limb(&e, r, 0);
4729 if (prec < e)
4730 goto general_case;
4731 }
4732 ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);
4606 }4733 }
4607 ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);4734 } else {
4608 }4735 if (rnd_mode != BF_RNDF) {
4609 } else {4736 bf_t *y1;
4610 if (rnd_mode != BF_RNDF) {4737 if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
4611 bf_t *y1;4738 /* the problem is reduced to a power to an integer */
4612 if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
4613 /* the problem is reduced to a power to an integer */
4614#if 04739#if 0
4615 printf("\nn=%ld\n", -y_emin);4740 printf("\nn=%" PRId64 "\n", -(int64_t)y_emin);
4616 bf_print_str("T", T);4741 bf_print_str("T", T);
4617 bf_print_str("r", r);4742 bf_print_str("r", r);
4618#endif4743#endif
4619 bf_set(T, r);4744 bf_set(T, r);
4620 y1 = &ytmp_s;4745 y1 = &ytmp_s;
4621 y1->tab = y->tab;4746 y1->tab = y->tab;
4622 y1->len = y->len;4747 y1->len = y->len;
4623 y1->sign = y->sign;4748 y1->sign = y->sign;
4624 y1->expn = y->expn - y_emin;4749 y1->expn = y->expn - y_emin;
4625 y = y1;4750 y = y1;
4626 goto int_pow;4751 goto int_pow;
4752 }
4627 }4753 }
4754 general_case:
4755 ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
4628 }4756 }
4629 general_case:
4630 ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
4631 }4757 }
4758 done:
4632 bf_delete(T);4759 bf_delete(T);
4633 r->sign = r_sign;4760 r->sign = r_sign;
4634 return ret;4761 return ret;
@@ -4649,7 +4776,7 @@ static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1) · 14 unmodified lines
4649 bf_delete(T);4776 bf_delete(T);
4650}4777}
4651 4778
4652int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)4779static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)
4653{4780{
4654 bf_context_t *s1 = a->ctx;4781 bf_context_t *s1 = a->ctx;
4655 bf_t T_s, *T = &T_s;4782 bf_t T_s, *T = &T_s;
@@ -4659,27 +4786,6 @@ int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) · 3 unmodified lines
4659 int is_neg;4786 int is_neg;
4660 4787
4661 assert(c != a && s != a);4788 assert(c != a && s != a);
4662 if (a->len == 0) {
4663 if (a->expn == BF_EXP_NAN) {
4664 if (c)
4665 bf_set_nan(c);
4666 if (s)
4667 bf_set_nan(s);
4668 return 0;
4669 } else if (a->expn == BF_EXP_INF) {
4670 if (c)
4671 bf_set_nan(c);
4672 if (s)
4673 bf_set_nan(s);
4674 return BF_ST_INVALID_OP;
4675 } else {
4676 if (c)
4677 bf_set_ui(c, 1);
4678 if (s)
4679 bf_set_zero(s, a->sign);
4680 return 0;
4681 }
4682 }
4683 4789
4684 bf_init(s1, T);4790 bf_init(s1, T);
4685 bf_init(s1, U);4791 bf_init(s1, U);
@@ -4699,10 +4805,10 @@ int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) · 13 unmodified lines
4699 slimb_t cancel;4805 slimb_t cancel;
4700 cancel = 0;4806 cancel = 0;
4701 for(;;) {4807 for(;;) {
4702 prec2 = prec1 + cancel;4808 prec2 = prec1 + a->expn + cancel;
4703 bf_const_pi(U, prec2, BF_RNDF);4809 bf_const_pi(U, prec2, BF_RNDF);
4704 bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);4810 bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);
4705 bf_remquo(&mod, T, a, U, prec2, BF_RNDN);4811 bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);
4706 // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);4812 // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);
4707 if (mod == 0 || (T->expn != BF_EXP_ZERO &&4813 if (mod == 0 || (T->expn != BF_EXP_ZERO &&
4708 (T->expn + prec2) >= (prec1 - 1)))4814 (T->expn + prec2) >= (prec1 - 1)))
@@ -4774,6 +4880,30 @@ static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 65 unmodified lines
4774 4880
4775int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)4881int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
4776{4882{
4883 if (a->len == 0) {
4884 if (a->expn == BF_EXP_NAN) {
4885 bf_set_nan(r);
4886 return 0;
4887 } else if (a->expn == BF_EXP_INF) {
4888 bf_set_nan(r);
4889 return BF_ST_INVALID_OP;
4890 } else {
4891 bf_set_ui(r, 1);
4892 return 0;
4893 }
4894 }
4895
4896 /* small argument case: result = 1+r(x) with r(x) = -x^2/2 +
4897 O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */
4898 if (a->expn < 0) {
4899 slimb_t e;
4900 e = 2 * a->expn - 1;
4901 if (e < -(prec + 2)) {
4902 bf_set_ui(r, 1);
4903 return bf_add_epsilon(r, r, e, 1, prec, flags);
4904 }
4905 }
4906
4777 return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);4907 return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);
4778}4908}
4779 4909
@@ -4784,15 +4914,6 @@ static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 4 unmodified lines
4784 4914
4785int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)4915int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
4786{4916{
4787 return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
4788}
4789
4790static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
4791{
4792 bf_context_t *s = r->ctx;
4793 bf_t T_s, *T = &T_s;
4794 limb_t prec1;
4795
4796 if (a->len == 0) {4917 if (a->len == 0) {
4797 if (a->expn == BF_EXP_NAN) {4918 if (a->expn == BF_EXP_NAN) {
4798 bf_set_nan(r);4919 bf_set_nan(r);
@@ -4806,6 +4927,26 @@ static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 7 unmodified lines
4806 }4927 }
4807 }4928 }
4808 4929
4930 /* small argument case: result = x+r(x) with r(x) = -x^3/6 +
4931 O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
4932 if (a->expn < 0) {
4933 slimb_t e;
4934 e = sat_add(2 * a->expn, a->expn - 2);
4935 if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
4936 bf_set(r, a);
4937 return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
4938 }
4939 }
4940
4941 return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
4942}
4943
4944static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
4945{
4946 bf_context_t *s = r->ctx;
4947 bf_t T_s, *T = &T_s;
4948 limb_t prec1;
4949
4809 /* XXX: precision analysis */4950 /* XXX: precision analysis */
4810 prec1 = prec + 8;4951 prec1 = prec + 8;
4811 bf_init(s, T);4952 bf_init(s, T);
@@ -4817,6 +4958,31 @@ static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 5 unmodified lines
4817 4958
4818int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)4959int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
4819{4960{
4961 assert(r != a);
4962 if (a->len == 0) {
4963 if (a->expn == BF_EXP_NAN) {
4964 bf_set_nan(r);
4965 return 0;
4966 } else if (a->expn == BF_EXP_INF) {
4967 bf_set_nan(r);
4968 return BF_ST_INVALID_OP;
4969 } else {
4970 bf_set_zero(r, a->sign);
4971 return 0;
4972 }
4973 }
4974
4975 /* small argument case: result = x+r(x) with r(x) = x^3/3 +
4976 O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
4977 if (a->expn < 0) {
4978 slimb_t e;
4979 e = sat_add(2 * a->expn, a->expn - 1);
4980 if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
4981 bf_set(r, a);
4982 return bf_add_epsilon(r, r, e, a->sign, prec, flags);
4983 }
4984 }
4985
4820 return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);4986 return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);
4821}4987}
4822 4988
@@ -4834,50 +5000,15 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, · 11 unmodified lines
4834 int cmp_1;5000 int cmp_1;
4835 slimb_t prec1, i, K, l;5001 slimb_t prec1, i, K, l;
4836 5002
4837 if (a->len == 0) {
4838 if (a->expn == BF_EXP_NAN) {
4839 bf_set_nan(r);
4840 return 0;
4841 } else {
4842 if (a->expn == BF_EXP_INF)
4843 i = 1 - 2 * a->sign;
4844 else
4845 i = 0;
4846 i += add_pi2;
4847 /* return i*(pi/2) with -1 <= i <= 2 */
4848 if (i == 0) {
4849 bf_set_zero(r, add_pi2 ? 0 : a->sign);
4850 return 0;
4851 } else {
4852 /* PI or PI/2 */
4853 bf_const_pi(r, prec, BF_RNDF);
4854 if (i != 2)
4855 bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
4856 r->sign = (i < 0);
4857 return BF_ST_INEXACT;
4858 }
4859 }
4860 }
4861
4862 bf_init(s, T);
4863 bf_set_ui(T, 1);
4864 cmp_1 = bf_cmpu(a, T);
4865 if (cmp_1 == 0 && !add_pi2) {
4866 /* short cut: abs(a) == 1 -> +/-pi/4 */
4867 bf_const_pi(r, prec, BF_RNDF);
4868 bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
4869 r->sign = a->sign;
4870 bf_delete(T);
4871 return BF_ST_INEXACT;
4872 }
4873
4874 /* XXX: precision analysis */5003 /* XXX: precision analysis */
4875 K = bf_isqrt((prec + 1) / 2);5004 K = bf_isqrt((prec + 1) / 2);
4876 l = prec / (2 * K) + 1;5005 l = prec / (2 * K) + 1;
4877 prec1 = prec + K + 2 * l + 32;5006 prec1 = prec + K + 2 * l + 32;
4878 // printf("prec=%ld K=%ld l=%ld prec1=%ld\n", prec, K, l, prec1);5007 // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);
4879 5008
4880 if (cmp_1 > 0) {5009 bf_init(s, T);
5010 cmp_1 = (a->expn >= 1); /* a >= 1 */
5011 if (cmp_1) {
4881 bf_set_ui(T, 1);5012 bf_set_ui(T, 1);
4882 bf_div(T, T, a, prec1, BF_RNDN);5013 bf_div(T, T, a, prec1, BF_RNDN);
4883 } else {5014 } else {
@@ -4945,6 +5076,47 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, · 61 unmodified lines
4945 5076
4946int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)5077int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
4947{5078{
5079 bf_context_t *s = r->ctx;
5080 bf_t T_s, *T = &T_s;
5081 int res;
5082
5083 if (a->len == 0) {
5084 if (a->expn == BF_EXP_NAN) {
5085 bf_set_nan(r);
5086 return 0;
5087 } else if (a->expn == BF_EXP_INF) {
5088 /* -PI/2 or PI/2 */
5089 bf_const_pi_signed(r, a->sign, prec, flags);
5090 bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5091 return BF_ST_INEXACT;
5092 } else {
5093 bf_set_zero(r, a->sign);
5094 return 0;
5095 }
5096 }
5097
5098 bf_init(s, T);
5099 bf_set_ui(T, 1);
5100 res = bf_cmpu(a, T);
5101 bf_delete(T);
5102 if (res == 0) {
5103 /* short cut: abs(a) == 1 -> +/-pi/4 */
5104 bf_const_pi_signed(r, a->sign, prec, flags);
5105 bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
5106 return BF_ST_INEXACT;
5107 }
5108
5109 /* small argument case: result = x+r(x) with r(x) = -x^3/3 +
5110 O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
5111 if (a->expn < 0) {
5112 slimb_t e;
5113 e = sat_add(2 * a->expn, a->expn - 1);
5114 if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
5115 bf_set(r, a);
5116 return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
5117 }
5118 }
5119
4948 return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);5120 return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);
4949}5121}
4950 5122
@@ -4998,38 +5170,6 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 47 unmodified lines
4998 BOOL is_acos = (BOOL)(intptr_t)opaque;5170 BOOL is_acos = (BOOL)(intptr_t)opaque;
4999 bf_t T_s, *T = &T_s;5171 bf_t T_s, *T = &T_s;
5000 limb_t prec1, prec2;5172 limb_t prec1, prec2;
5001 int res;
5002
5003 if (a->len == 0) {
5004 if (a->expn == BF_EXP_NAN) {
5005 bf_set_nan(r);
5006 return 0;
5007 } else if (a->expn == BF_EXP_INF) {
5008 bf_set_nan(r);
5009 return BF_ST_INVALID_OP;
5010 } else {
5011 if (is_acos) {
5012 bf_const_pi(r, prec, BF_RNDF);
5013 bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5014 return BF_ST_INEXACT;
5015 } else {
5016 bf_set_zero(r, a->sign);
5017 return 0;
5018 }
5019 }
5020 }
5021 bf_init(s, T);
5022 bf_set_ui(T, 1);
5023 res = bf_cmpu(a, T);
5024 if (res > 0) {
5025 bf_delete(T);
5026 bf_set_nan(r);
5027 return BF_ST_INVALID_OP;
5028 } else if (res == 0 && a->sign == 0 && is_acos) {
5029 bf_set_zero(r, 0);
5030 bf_delete(T);
5031 return 0;
5032 }
5033 5173
5034 /* asin(x) = atan(x/sqrt(1-x^2)) 5174 /* asin(x) = atan(x/sqrt(1-x^2))
5035 acos(x) = pi/2 - asin(x) */5175 acos(x) = pi/2 - asin(x) */
@@ -5041,6 +5181,7 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 5 unmodified lines
5041 prec2 = BF_PREC_INF;5181 prec2 = BF_PREC_INF;
5042 else5182 else
5043 prec2 = prec1;5183 prec2 = prec1;
5184 bf_init(s, T);
5044 bf_mul(T, a, a, prec2, BF_RNDN);5185 bf_mul(T, a, a, prec2, BF_RNDN);
5045 bf_neg(T);5186 bf_neg(T);
5046 bf_add_si(T, T, 1, prec2, BF_RNDN);5187 bf_add_si(T, T, 1, prec2, BF_RNDN);
@@ -5056,11 +5197,76 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 9 unmodified lines
5056 5197
5057int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)5198int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
5058{5199{
5200 bf_context_t *s = r->ctx;
5201 bf_t T_s, *T = &T_s;
5202 int res;
5203
5204 if (a->len == 0) {
5205 if (a->expn == BF_EXP_NAN) {
5206 bf_set_nan(r);
5207 return 0;
5208 } else if (a->expn == BF_EXP_INF) {
5209 bf_set_nan(r);
5210 return BF_ST_INVALID_OP;
5211 } else {
5212 bf_set_zero(r, a->sign);
5213 return 0;
5214 }
5215 }
5216 bf_init(s, T);
5217 bf_set_ui(T, 1);
5218 res = bf_cmpu(a, T);
5219 bf_delete(T);
5220 if (res > 0) {
5221 bf_set_nan(r);
5222 return BF_ST_INVALID_OP;
5223 }
5224
5225 /* small argument case: result = x+r(x) with r(x) = x^3/6 +
5226 O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
5227 if (a->expn < 0) {
5228 slimb_t e;
5229 e = sat_add(2 * a->expn, a->expn - 2);
5230 if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
5231 bf_set(r, a);
5232 return bf_add_epsilon(r, r, e, a->sign, prec, flags);
5233 }
5234 }
5235
5059 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);5236 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);
5060}5237}
5061 5238
5062int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)5239int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
5063{5240{
5241 bf_context_t *s = r->ctx;
5242 bf_t T_s, *T = &T_s;
5243 int res;
5244
5245 if (a->len == 0) {
5246 if (a->expn == BF_EXP_NAN) {
5247 bf_set_nan(r);
5248 return 0;
5249 } else if (a->expn == BF_EXP_INF) {
5250 bf_set_nan(r);
5251 return BF_ST_INVALID_OP;
5252 } else {
5253 bf_const_pi(r, prec, flags);
5254 bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5255 return BF_ST_INEXACT;
5256 }
5257 }
5258 bf_init(s, T);
5259 bf_set_ui(T, 1);
5260 res = bf_cmpu(a, T);
5261 bf_delete(T);
5262 if (res > 0) {
5263 bf_set_nan(r);
5264 return BF_ST_INVALID_OP;
5265 } else if (res == 0 && a->sign == 0) {
5266 bf_set_zero(r, 0);
5267 return 0;
5268 }
5269
5064 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);5270 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);
5065}5271}
5066 5272
@@ -5124,14 +5330,14 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 57 unmodified lines
5124 5330
5125#endif /* LIMB_BITS != 64 */5331#endif /* LIMB_BITS != 64 */
5126 5332
5127static inline limb_t shrd(limb_t low, limb_t high, long shift)5333static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)
5128{5334{
5129 if (shift != 0)5335 if (shift != 0)
5130 low = (low >> shift) | (high << (LIMB_BITS - shift));5336 low = (low >> shift) | (high << (LIMB_BITS - shift));
5131 return low;5337 return low;
5132}5338}
5133 5339
5134static inline limb_t shld(limb_t a1, limb_t a0, long shift)5340static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)
5135{5341{
5136 if (shift != 0)5342 if (shift != 0)
5137 return (a1 << shift) | (a0 >> (LIMB_BITS - shift));5343 return (a1 << shift) | (a0 >> (LIMB_BITS - shift));
@@ -5185,21 +5391,18 @@ do {\ · 47 unmodified lines
5185/* fast integer division by a fixed constant */5391/* fast integer division by a fixed constant */
5186 5392
5187typedef struct FastDivData {5393typedef struct FastDivData {
5188 limb_t d; /* divisor (only user visible field) */
5189 limb_t m1; /* multiplier */5394 limb_t m1; /* multiplier */
5190 int shift1;5395 int8_t shift1;
5191 int shift2;5396 int8_t shift2;
5192} FastDivData;5397} FastDivData;
5193 5398
5194#if 1
5195/* From "Division by Invariant Integers using Multiplication" by5399/* From "Division by Invariant Integers using Multiplication" by
5196 Torborn Granlund and Peter L. Montgomery */5400 Torborn Granlund and Peter L. Montgomery */
5197/* d must be != 0 */5401/* d must be != 0 */
5198static inline void fast_udiv_init(FastDivData *s, limb_t d)5402static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)
5199{5403{
5200 int l;5404 int l;
5201 limb_t q, r, m1;5405 limb_t q, r, m1;
5202 s->d = d;
5203 if (d == 1)5406 if (d == 1)
5204 l = 0;5407 l = 0;
5205 else5408 else
@@ -5225,52 +5428,78 @@ static inline limb_t fast_udiv(limb_t a, const FastDivData *s) · 19 unmodified lines
5225 return (t1 + t0) >> s->shift2;5428 return (t1 + t0) >> s->shift2;
5226}5429}
5227 5430
5228static inline limb_t fast_urem(limb_t a, const FastDivData *s)5431/* contains 10^i */
5229{5432const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {
5230 limb_t q;5433 1U,
5231 q = fast_udiv(a, s);5434 10U,
5232 return a - q * s->d;5435 100U,
5233}5436 1000U,
5437 10000U,
5438 100000U,
5439 1000000U,
5440 10000000U,
5441 100000000U,
5442 1000000000U,
5443#if LIMB_BITS == 64
5444 10000000000U,
5445 100000000000U,
5446 1000000000000U,
5447 10000000000000U,
5448 100000000000000U,
5449 1000000000000000U,
5450 10000000000000000U,
5451 100000000000000000U,
5452 1000000000000000000U,
5453 10000000000000000000U,
5454#endif
5455};
5234 5456
5235#define fast_udivrem(q, r, a, s) q = fast_udiv(a, s), r = a - q * (s)->d5457/* precomputed from fast_udiv_init(10^i) */
5236 5458static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {
5459#if LIMB_BITS == 32
5460 { 0x00000001, 0, 0 },
5461 { 0x9999999a, 1, 3 },
5462 { 0x47ae147b, 1, 6 },
5463 { 0x0624dd30, 1, 9 },
5464 { 0xa36e2eb2, 1, 13 },
5465 { 0x4f8b588f, 1, 16 },
5466 { 0x0c6f7a0c, 1, 19 },
5467 { 0xad7f29ac, 1, 23 },
5468 { 0x5798ee24, 1, 26 },
5469 { 0x12e0be83, 1, 29 },
5237#else5470#else
5238 5471 { 0x0000000000000001, 0, 0 },
5239static inline void fast_udiv_init(FastDivData *s, limb_t d)5472 { 0x999999999999999a, 1, 3 },
5240{5473 { 0x47ae147ae147ae15, 1, 6 },
5241 s->d = d;5474 { 0x0624dd2f1a9fbe77, 1, 9 },
5242}5475 { 0xa36e2eb1c432ca58, 1, 13 },
5243static inline limb_t fast_udiv(limb_t a, const FastDivData *s)5476 { 0x4f8b588e368f0847, 1, 16 },
5244{5477 { 0x0c6f7a0b5ed8d36c, 1, 19 },
5245 return a / s->d;5478 { 0xad7f29abcaf48579, 1, 23 },
5246}5479 { 0x5798ee2308c39dfa, 1, 26 },
5247static inline limb_t fast_urem(limb_t a, const FastDivData *s)5480 { 0x12e0be826d694b2f, 1, 29 },
5248{5481 { 0xb7cdfd9d7bdbab7e, 1, 33 },
5249 return a % s->d;5482 { 0x5fd7fe17964955fe, 1, 36 },
5250}5483 { 0x19799812dea11198, 1, 39 },
5251 5484 { 0xc25c268497681c27, 1, 43 },
5252#define fast_udivrem(q, r, a, s) q = a / (s)->d, r = a % (s)->d5485 { 0x6849b86a12b9b01f, 1, 46 },
5253 5486 { 0x203af9ee756159b3, 1, 49 },
5487 { 0xcd2b297d889bc2b7, 1, 53 },
5488 { 0x70ef54646d496893, 1, 56 },
5489 { 0x2725dd1d243aba0f, 1, 59 },
5490 { 0xd83c94fb6d2ac34d, 1, 63 },
5254#endif5491#endif
5492};
5255 5493
5256/* contains 10^i */5494/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */
5257/* XXX: make it const */5495static inline limb_t fast_shr_dec(limb_t a, int shift)
5258limb_t mp_pow_dec[LIMB_DIGITS + 1];
5259static FastDivData mp_pow_div[LIMB_DIGITS + 1];
5260
5261static void mp_pow_init(void)
5262{5496{
5263 limb_t a;5497 return fast_udiv(a, &mp_pow_div[shift]);
5264 int i;
5265
5266 a = 1;
5267 for(i = 0; i <= LIMB_DIGITS; i++) {
5268 mp_pow_dec[i] = a;
5269 fast_udiv_init(&mp_pow_div[i], a);
5270 a = a * 10;
5271 }
5272}5498}
5273 5499
5500/* division and remainder by 10^shift */
5501#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]
5502
5274limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, 5503limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
5275 mp_size_t n, limb_t carry)5504 mp_size_t n, limb_t carry)
5276{5505{
@@ -5653,7 +5882,7 @@ static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, · 376 unmodified lines
5653 l = high;5882 l = high;
5654 for(i = n - 1; i >= 0; i--) {5883 for(i = n - 1; i >= 0; i--) {
5655 a = tab[i];5884 a = tab[i];
5656 fast_udivrem(q, r, a, &mp_pow_div[shift]);5885 fast_shr_rem_dec(q, r, a, shift);
5657 tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];5886 tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];
5658 l = r;5887 l = r;
5659 }5888 }
@@ -5671,7 +5900,7 @@ static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, · 11 unmodified lines
5671 l = low;5900 l = low;
5672 for(i = 0; i < n; i++) {5901 for(i = 0; i < n; i++) {
5673 a = tab[i];5902 a = tab[i];
5674 fast_udivrem(q, r, a, &mp_pow_div[LIMB_DIGITS - shift]);5903 fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);
5675 tab_r[i] = r * mp_pow_dec[shift] + l;5904 tab_r[i] = r * mp_pow_dec[shift] + l;
5676 l = q;5905 l = q;
5677 }5906 }
@@ -6011,7 +6240,7 @@ static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos) · 333 unmodified lines
6011 return 0;6240 return 0;
6012 pos = (limb_t)bit_pos / LIMB_DIGITS;6241 pos = (limb_t)bit_pos / LIMB_DIGITS;
6013 shift = (limb_t)bit_pos % LIMB_DIGITS;6242 shift = (limb_t)bit_pos % LIMB_DIGITS;
6014 fast_udivrem(q, v, r->tab[pos], &mp_pow_div[shift + 1]);6243 fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);
6015 (void)q;6244 (void)q;
6016 if (v != 0)6245 if (v != 0)
6017 return 1;6246 return 1;
@@ -6032,7 +6261,7 @@ static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos) · 14 unmodified lines
6032 if (i < 0 || i >= len)6261 if (i < 0 || i >= len)
6033 return 0;6262 return 0;
6034 shift = pos - i * LIMB_DIGITS;6263 shift = pos - i * LIMB_DIGITS;
6035 return fast_udiv(tab[i], &mp_pow_div[shift]) % 10;6264 return fast_shr_dec(tab[i], shift) % 10;
6036}6265}
6037 6266
6038#if 06267#if 0
@@ -6056,7 +6285,7 @@ static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos) · 17 unmodified lines
6056 a1 = tab[i];6285 a1 = tab[i];
6057 else6286 else
6058 a1 = 0;6287 a1 = 0;
6059 return fast_udiv(a0, &mp_pow_div[shift]) +6288 return fast_shr_dec(a0, shift) +
6060 fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *6289 fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *
6061 mp_pow_dec[shift];6290 mp_pow_dec[shift];
6062 }6291 }
@@ -6108,13 +6337,8 @@ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, · 45 unmodified lines
6108 case BF_RNDF:6337 case BF_RNDF:
6109 add_one = (digit1 >= 5);6338 add_one = (digit1 >= 5);
6110 break;6339 break;
6111 case BF_RNDNU:6340 case BF_RNDA:
6112 if (digit1 >= 5) {6341 add_one = inexact;
6113 if (r->sign)
6114 add_one = (digit0 != 0);
6115 else
6116 add_one = 1;
6117 }
6118 break;6342 break;
6119 default:6343 default:
6120 abort();6344 abort();
@@ -6135,8 +6359,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 14 unmodified lines
6135 int shift, add_one, rnd_mode, ret;6359 int shift, add_one, rnd_mode, ret;
6136 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;6360 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
6137 6361
6138 /* e_min and e_max are computed to match the IEEE 754 conventions */6362 /* XXX: align to IEEE 754 2008 for decimal numbers ? */
6139 /* XXX: does not matter for decimal numbers */
6140 e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);6363 e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
6141 e_min = -e_range + 3;6364 e_min = -e_range + 3;
6142 e_max = e_range;6365 e_max = e_range;
@@ -6147,6 +6370,11 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 4 unmodified lines
6147 prec = r->expn + prec1;6370 prec = r->expn + prec1;
6148 else6371 else
6149 prec = prec1;6372 prec = prec1;
6373 } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
6374 /* restrict the precision in case of potentially subnormal
6375 result */
6376 assert(prec1 != BF_PREC_INF);
6377 prec = prec1 - (e_min - r->expn);
6150 } else {6378 } else {
6151 prec = prec1;6379 prec = prec1;
6152 }6380 }
@@ -6183,10 +6411,16 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 30 unmodified lines
6183 6411
6184 /* check underflow */6412 /* check underflow */
6185 if (unlikely(r->expn < e_min)) {6413 if (unlikely(r->expn < e_min)) {
6186 underflow:6414 if (flags & BF_FLAG_SUBNORMAL) {
6187 bfdec_set_zero(r, r->sign);6415 /* if inexact, also set the underflow flag */
6188 ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;6416 if (ret & BF_ST_INEXACT)
6189 return ret;6417 ret |= BF_ST_UNDERFLOW;
6418 } else {
6419 underflow:
6420 bfdec_set_zero(r, r->sign);
6421 ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
6422 return ret;
6423 }
6190 }6424 }
6191 6425
6192 /* check overflow */6426 /* check overflow */
@@ -6202,7 +6436,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 9 unmodified lines
6202 if (i >= 0) {6436 if (i >= 0) {
6203 shift = smod(bit_pos, LIMB_DIGITS);6437 shift = smod(bit_pos, LIMB_DIGITS);
6204 if (shift != 0) {6438 if (shift != 0) {
6205 r->tab[i] = fast_udiv(r->tab[i], &mp_pow_div[shift]) *6439 r->tab[i] = fast_shr_dec(r->tab[i], shift) *
6206 mp_pow_dec[shift];6440 mp_pow_dec[shift];
6207 }6441 }
6208 } else {6442 } else {
@@ -6571,10 +6805,10 @@ static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 362 unmodified lines
6571 /* number of digits after the decimal point */6805 /* number of digits after the decimal point */
6572 /* XXX: check (2 extra digits for rounding + 2 digits) */6806 /* XXX: check (2 extra digits for rounding + 2 digits) */
6573 precl = (bf_max(a->expn - b->expn, 0) + 2 +6807 precl = (bf_max(a->expn - b->expn, 0) + 2 +
6574 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;6808 prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
6575 } else {6809 } else {
6576 /* number of limbs of the quotient (2 extra digits for rounding) */6810 /* number of limbs of the quotient (2 extra digits for rounding) */
6577 precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;6811 precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
6578 }6812 }
6579 n = bf_max(a->len, precl);6813 n = bf_max(a->len, precl);
6580 6814
@@ -6679,8 +6913,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 98 unmodified lines
6679 }6913 }
6680 6914
6681 q_sign = a->sign ^ b->sign;6915 q_sign = a->sign ^ b->sign;
6682 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||6916 is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
6683 rnd_mode == BF_RNDNU);
6684 switch(rnd_mode) {6917 switch(rnd_mode) {
6685 default:6918 default:
6686 case BF_RNDZ:6919 case BF_RNDZ:
@@ -6694,12 +6927,12 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 7 unmodified lines
6694 case BF_RNDU:6927 case BF_RNDU:
6695 is_ceil = q_sign ^ 1;6928 is_ceil = q_sign ^ 1;
6696 break;6929 break;
6930 case BF_RNDA:
6931 is_ceil = TRUE;
6932 break;
6697 case BF_DIVREM_EUCLIDIAN:6933 case BF_DIVREM_EUCLIDIAN:
6698 is_ceil = a->sign;6934 is_ceil = a->sign;
6699 break;6935 break;
6700 case BF_RNDNU:
6701 /* XXX: unsupported yet */
6702 abort();
6703 }6936 }
6704 6937
6705 a1->expn = a->expn;6938 a1->expn = a->expn;
@@ -6756,14 +6989,14 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 50 unmodified lines
6756 return BF_ST_MEM_ERROR;6989 return BF_ST_MEM_ERROR;
6757}6990}
6758 6991
6759int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,6992int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
6760 bf_flags_t flags)6993 bf_flags_t flags, int rnd_mode)
6761{6994{
6762 bfdec_t q_s, *q = &q_s;6995 bfdec_t q_s, *q = &q_s;
6763 int ret;6996 int ret;
6764 6997
6765 bfdec_init(r->ctx, q);6998 bfdec_init(r->ctx, q);
6766 ret = bfdec_divrem(q, r, a, b, prec, flags, BF_RNDZ);6999 ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);
6767 bfdec_delete(q);7000 bfdec_delete(q);
6768 return ret;7001 return ret;
6769}7002}
@@ -6779,7 +7012,7 @@ int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags) · 9 unmodified lines
6779 bf_context_t *s = a->ctx;7012 bf_context_t *s = a->ctx;
6780 int ret, k;7013 int ret, k;
6781 limb_t *a1, v;7014 limb_t *a1, v;
6782 slimb_t n, n1;7015 slimb_t n, n1, prec1;
6783 limb_t res;7016 limb_t res;
6784 7017
6785 assert(r != a);7018 assert(r != a);
@@ -6798,9 +7031,14 @@ int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags) · 12 unmodified lines
6798 bfdec_set_nan(r);7031 bfdec_set_nan(r);
6799 ret = BF_ST_INVALID_OP;7032 ret = BF_ST_INVALID_OP;
6800 } else {7033 } else {
7034 if (flags & BF_FLAG_RADPNT_PREC) {
7035 prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);
7036 } else {
7037 prec1 = prec;
7038 }
6801 /* convert the mantissa to an integer with at least 2 *7039 /* convert the mantissa to an integer with at least 2 *
6802 prec + 4 digits */7040 prec + 4 digits */
6803 n = (2 * (prec + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);7041 n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);
6804 if (bfdec_resize(r, n))7042 if (bfdec_resize(r, n))
6805 goto fail;7043 goto fail;
6806 a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);7044 a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
@@ -6869,7 +7107,7 @@ int bfdec_get_int32(int *pres, const bfdec_t *a) · 62 unmodified lines
6869 v = 0;7107 v = 0;
6870 ret = 0;7108 ret = 0;
6871 } else if (a->expn <= 9) {7109 } else if (a->expn <= 9) {
6872 v = fast_udiv(a->tab[a->len - 1], &mp_pow_div[LIMB_DIGITS - a->expn]);7110 v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
6873 if (a->sign)7111 if (a->sign)
6874 v = -v;7112 v = -v;
6875 ret = 0;7113 ret = 0;
@@ -6877,7 +7115,7 @@ int bfdec_get_int32(int *pres, const bfdec_t *a) · 1 unmodified line
6877 uint64_t v1;7115 uint64_t v1;
6878 uint32_t v_max;7116 uint32_t v_max;
6879#if LIMB_BITS == 647117#if LIMB_BITS == 64
6880 v1 = fast_udiv(a->tab[a->len - 1], &mp_pow_div[LIMB_DIGITS - a->expn]);7118 v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
6881#else7119#else
6882 v1 = (uint64_t)a->tab[a->len - 1] * 10 +7120 v1 = (uint64_t)a->tab[a->len - 1] * 10 +
6883 get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);7121 get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);
libbf.h+77−42
@@ -41,8 +41,8 @@ typedef unsigned __int128 uint128_t; · 40 unmodified lines
41typedef int64_t slimb_t;41typedef int64_t slimb_t;
42typedef uint64_t limb_t;42typedef uint64_t limb_t;
43typedef uint128_t dlimb_t;43typedef uint128_t dlimb_t;
44#define EXP_MIN INT64_MIN44#define BF_RAW_EXP_MIN INT64_MIN
45#define EXP_MAX INT64_MAX45#define BF_RAW_EXP_MAX INT64_MAX
46 46
47#define LIMB_DIGITS 1947#define LIMB_DIGITS 19
48#define BF_DEC_BASE UINT64_C(10000000000000000000)48#define BF_DEC_BASE UINT64_C(10000000000000000000)
@@ -52,8 +52,8 @@ typedef uint128_t dlimb_t; · 3 unmodified lines
52typedef int32_t slimb_t;52typedef int32_t slimb_t;
53typedef uint32_t limb_t;53typedef uint32_t limb_t;
54typedef uint64_t dlimb_t;54typedef uint64_t dlimb_t;
55#define EXP_MIN INT32_MIN55#define BF_RAW_EXP_MIN INT32_MIN
56#define EXP_MAX INT32_MAX56#define BF_RAW_EXP_MAX INT32_MAX
57 57
58#define LIMB_DIGITS 958#define LIMB_DIGITS 9
59#define BF_DEC_BASE 1000000000U59#define BF_DEC_BASE 1000000000U
@@ -61,10 +61,17 @@ typedef uint64_t dlimb_t; · 1 unmodified line
61#endif61#endif
62 62
63/* in bits */63/* in bits */
64/* minimum number of bits for the exponent */
64#define BF_EXP_BITS_MIN 365#define BF_EXP_BITS_MIN 3
65#define BF_EXP_BITS_MAX (LIMB_BITS - 2)66/* maximum number of bits for the exponent */
67#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
68/* extended range for exponent, used internally */
69#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
70/* minimum possible precision */
66#define BF_PREC_MIN 271#define BF_PREC_MIN 2
67#define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2)72/* minimum possible precision */
73#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
74/* some operations support infinite precision */
68#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */75#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
69 76
70#if LIMB_BITS == 6477#if LIMB_BITS == 64
@@ -73,9 +80,9 @@ typedef uint64_t dlimb_t; · 2 unmodified lines
73#define BF_CHKSUM_MOD 975620677U80#define BF_CHKSUM_MOD 975620677U
74#endif81#endif
75 82
76#define BF_EXP_ZERO EXP_MIN83#define BF_EXP_ZERO BF_RAW_EXP_MIN
77#define BF_EXP_INF (EXP_MAX - 1)84#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
78#define BF_EXP_NAN EXP_MAX85#define BF_EXP_NAN BF_RAW_EXP_MAX
79 86
80/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,87/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
81 +/-infinity is represented with expn = BF_EXP_INF and len = 0,88 +/-infinity is represented with expn = BF_EXP_INF and len = 0,
@@ -101,27 +108,29 @@ typedef struct { · 19 unmodified lines
101typedef enum {108typedef enum {
102 BF_RNDN, /* round to nearest, ties to even */109 BF_RNDN, /* round to nearest, ties to even */
103 BF_RNDZ, /* round to zero */110 BF_RNDZ, /* round to zero */
104 BF_RNDD, /* round to -inf */111 BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
105 BF_RNDU, /* round to +inf */112 BF_RNDU, /* round to +inf */
106 BF_RNDNA, /* round to nearest, ties away from zero */113 BF_RNDNA, /* round to nearest, ties away from zero */
107 BF_RNDNU, /* round to nearest, ties to +inf */114 BF_RNDA, /* round away from zero */
108 BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,115 BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
109 inexact flag is always set) */116 inexact flag is always set) */
110} bf_rnd_t;117} bf_rnd_t;
111 118
112/* allow subnormal numbers. Only available if the number of exponent119/* allow subnormal numbers. Only available if the number of exponent
113 bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF. Not supported120 bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
114 for decimal floating point numbers. */
115#define BF_FLAG_SUBNORMAL (1 << 3)121#define BF_FLAG_SUBNORMAL (1 << 3)
116/* 'prec' is the precision after the radix point instead of the whole122/* 'prec' is the precision after the radix point instead of the whole
117 mantissa. Can only be used with bf_round(), bfdec_round() and123 mantissa. Can only be used with bf_round() and
118 bfdev_div(). */124 bfdec_[add|sub|mul|div|sqrt|round](). */
119#define BF_FLAG_RADPNT_PREC (1 << 4)125#define BF_FLAG_RADPNT_PREC (1 << 4)
120 126
121#define BF_RND_MASK 0x7127#define BF_RND_MASK 0x7
122#define BF_EXP_BITS_SHIFT 5128#define BF_EXP_BITS_SHIFT 5
123#define BF_EXP_BITS_MASK 0x3f129#define BF_EXP_BITS_MASK 0x3f
124 130
131/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
132#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
133
125/* contains the rounding mode and number of exponents bits */134/* contains the rounding mode and number of exponents bits */
126typedef uint32_t bf_flags_t;135typedef uint32_t bf_flags_t;
127 136
@@ -142,12 +151,17 @@ typedef struct bf_context_t { · 14 unmodified lines
142 151
143static inline int bf_get_exp_bits(bf_flags_t flags)152static inline int bf_get_exp_bits(bf_flags_t flags)
144{153{
145 return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK);154 int e;
155 e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
156 if (e == BF_EXP_BITS_MASK)
157 return BF_EXP_BITS_MAX + 1;
158 else
159 return BF_EXP_BITS_MAX - e;
146}160}
147 161
148static inline bf_flags_t bf_set_exp_bits(int n)162static inline bf_flags_t bf_set_exp_bits(int n)
149{163{
150 return (BF_EXP_BITS_MAX - n) << BF_EXP_BITS_SHIFT;164 return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
151}165}
152 166
153/* returned status */167/* returned status */
@@ -249,9 +263,22 @@ int bf_set_float64(bf_t *a, double d); · 95 unmodified lines
249 263
250int bf_cmpu(const bf_t *a, const bf_t *b);264int bf_cmpu(const bf_t *a, const bf_t *b);
251int bf_cmp_full(const bf_t *a, const bf_t *b);265int bf_cmp_full(const bf_t *a, const bf_t *b);
252int bf_cmp_eq(const bf_t *a, const bf_t *b);266int bf_cmp(const bf_t *a, const bf_t *b);
253int bf_cmp_le(const bf_t *a, const bf_t *b);267static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
254int bf_cmp_lt(const bf_t *a, const bf_t *b);268{
269 return bf_cmp(a, b) == 0;
270}
271
272static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
273{
274 return bf_cmp(a, b) <= 0;
275}
276
277static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
278{
279 return bf_cmp(a, b) < 0;
280}
281
255int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);282int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
256int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);283int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
257int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);284int 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) · 6 unmodified lines
264#define BF_DIVREM_EUCLIDIAN BF_RNDF291#define BF_DIVREM_EUCLIDIAN BF_RNDF
265int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,292int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
266 limb_t prec, bf_flags_t flags, int rnd_mode);293 limb_t prec, bf_flags_t flags, int rnd_mode);
267int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,294int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
268 bf_flags_t flags);295 bf_flags_t flags, int rnd_mode);
269int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
270 bf_flags_t flags);
271int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,296int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
272 bf_flags_t flags);297 bf_flags_t flags, int rnd_mode);
273/* round to integer with infinite precision */298/* round to integer with infinite precision */
274int bf_rint(bf_t *r, int rnd_mode);299int bf_rint(bf_t *r, int rnd_mode);
275int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);300int 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, · 28 unmodified lines
304/* Conversion of floating point number to string. Return a null329/* Conversion of floating point number to string. Return a null
305 terminated string or NULL if memory error. *plen contains its330 terminated string or NULL if memory error. *plen contains its
306 length if plen != NULL. The exponent letter is "e" for base 10,331 length if plen != NULL. The exponent letter is "e" for base 10,
307 "p" for bases 2, 8, 16 with the binary exponent and "@" for the332 "p" for bases 2, 8, 16 with a binary exponent and "@" for the other
308 other bases. */333 bases. */
309 334
310#define BF_FTOA_FORMAT_MASK (3 << 16)335#define BF_FTOA_FORMAT_MASK (3 << 16)
311 336
@@ -316,17 +341,23 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 4 unmodified lines
316/* fractional format: prec digits after the decimal point rounded with341/* fractional format: prec digits after the decimal point rounded with
317 (flags & BF_RND_MASK) */342 (flags & BF_RND_MASK) */
318#define BF_FTOA_FORMAT_FRAC (1 << 16)343#define BF_FTOA_FORMAT_FRAC (1 << 16)
319/* free format: use as many digits as necessary so that bf_atof()344/* free format:
320 return the same number when using precision 'prec', rounding to345
321 nearest and the subnormal+exponent configuration of 'flags'. The346 For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
322 result is meaningful only if 'a' is already rounded to the wanted347 number of digits to represent 'a'. The precision and the rounding
323 precision.348 mode are ignored.
324 349
325 Infinite precision (BF_PREC_INF) is supported when the radix is a350 For the non binary radices with bf_ftoa(): use as many digits as
326 power of two. */351 necessary so that bf_atof() return the same number when using
352 precision 'prec', rounding to nearest and the subnormal
353 configuration of 'flags'. The result is meaningful only if 'a' is
354 already rounded to 'prec' bits. If the subnormal flag is set, the
355 exponent in 'flags' must also be set to the desired exponent range.
356*/
327#define BF_FTOA_FORMAT_FREE (2 << 16)357#define BF_FTOA_FORMAT_FREE (2 << 16)
328/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits358/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
329 (takes more computation time). */359 (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
360 binary radices with bf_ftoa() and for bfdec_ftoa(). */
330#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)361#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
331 362
332/* force exponential notation for fixed or free format */363/* 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); · 37 unmodified lines
370int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);401int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
371int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);402int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
372int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);403int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
373#define BF_POW_JS_QUICKS (1 << 16)404#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
374int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);405int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
375int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);406int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
376int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);407int 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) · 71 unmodified lines
448{479{
449 return bf_cmp_full((const bf_t *)a, (const bf_t *)b);480 return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
450}481}
482static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
483{
484 return bf_cmp((const bf_t *)a, (const bf_t *)b);
485}
451static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)486static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
452{487{
453 return bf_cmp_eq((const bf_t *)a, (const bf_t *)b);488 return bfdec_cmp(a, b) == 0;
454}489}
455static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)490static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
456{491{
457 return bf_cmp_le((const bf_t *)a, (const bf_t *)b);492 return bfdec_cmp(a, b) <= 0;
458}493}
459static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)494static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
460{495{
461 return bf_cmp_lt((const bf_t *)a, (const bf_t *)b);496 return bfdec_cmp(a, b) < 0;
462}497}
463 498
464int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,499int 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, · 10 unmodified lines
475 bf_flags_t flags);510 bf_flags_t flags);
476int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,511int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
477 limb_t prec, bf_flags_t flags, int rnd_mode);512 limb_t prec, bf_flags_t flags, int rnd_mode);
478int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,513int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
479 bf_flags_t flags);514 bf_flags_t flags, int rnd_mode);
480int bfdec_rint(bfdec_t *r, int rnd_mode);515int bfdec_rint(bfdec_t *r, int rnd_mode);
481int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);516int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
482int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);517int 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, · 5 unmodified lines
488 limb_t prec, bf_flags_t flags);523 limb_t prec, bf_flags_t flags);
489 524
490/* the following functions are exported for testing only. */525/* the following functions are exported for testing only. */
491extern limb_t mp_pow_dec[LIMB_DIGITS + 1];526extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
492void bfdec_print_str(const char *str, const bfdec_t *a);527void bfdec_print_str(const char *str, const bfdec_t *a);
493static inline int bfdec_resize(bfdec_t *r, limb_t len)528static inline int bfdec_resize(bfdec_t *r, limb_t len)
494{529{
qjs.c+22−4
@@ -41,9 +41,6 @@ · 40 unmodified lines
41#include "cutils.h"41#include "cutils.h"
42#include "quickjs-libc.h"42#include "quickjs-libc.h"
43 43
44/* enable bignums */
45#define CONFIG_BIGNUM
46
47extern const uint8_t qjsc_repl[];44extern const uint8_t qjsc_repl[];
48extern const uint32_t qjsc_repl_size;45extern const uint32_t qjsc_repl_size;
49#ifdef CONFIG_BIGNUM46#ifdef CONFIG_BIGNUM
@@ -258,12 +255,13 @@ static const JSMallocFunctions trace_mf = { · 208 unmodified lines
258void help(void)255void help(void)
259{256{
260 printf("QuickJS version " CONFIG_VERSION "\n"257 printf("QuickJS version " CONFIG_VERSION "\n"
261 "usage: " PROG_NAME " [options] [file]\n"258 "usage: " PROG_NAME " [options] [file [args]]\n"
262 "-h --help list options\n"259 "-h --help list options\n"
263 "-e --eval EXPR evaluate EXPR\n"260 "-e --eval EXPR evaluate EXPR\n"
264 "-i --interactive go to interactive mode\n"261 "-i --interactive go to interactive mode\n"
265 "-m --module load as ES6 module (default=autodetect)\n"262 "-m --module load as ES6 module (default=autodetect)\n"
266 " --script load as ES6 script (default=autodetect)\n"263 " --script load as ES6 script (default=autodetect)\n"
264 "-I --include file include an additional file\n"
267 " --std make 'std' and 'os' available to the loaded script\n"265 " --std make 'std' and 'os' available to the loaded script\n"
268#ifdef CONFIG_BIGNUM266#ifdef CONFIG_BIGNUM
269 " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"267 " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
@@ -292,6 +290,8 @@ int main(int argc, char **argv) · 22 unmodified lines
292 int load_std = 0;290 int load_std = 0;
293 int dump_unhandled_promise_rejection = 0;291 int dump_unhandled_promise_rejection = 0;
294 size_t memory_limit = 0;292 size_t memory_limit = 0;
293 char *include_list[32];
294 int i, include_count = 0;
295#ifdef CONFIG_BIGNUM295#ifdef CONFIG_BIGNUM
296 int load_jscalc, bignum_ext = 0;296 int load_jscalc, bignum_ext = 0;
297#endif297#endif
@@ -345,6 +345,18 @@ int main(int argc, char **argv) · 47 unmodified lines
345 fprintf(stderr, "qjs: missing expression for -e\n");345 fprintf(stderr, "qjs: missing expression for -e\n");
346 exit(2);346 exit(2);
347 }347 }
348 if (opt == 'I' || !strcmp(longopt, "include")) {
349 if (optind >= argc) {
350 fprintf(stderr, "expecting filename");
351 exit(1);
352 }
353 if (include_count >= countof(include_list)) {
354 fprintf(stderr, "too many included files");
355 exit(1);
356 }
357 include_list[include_count++] = argv[optind++];
358 continue;
359 }
348 if (opt == 'i' || !strcmp(longopt, "interactive")) {360 if (opt == 'i' || !strcmp(longopt, "interactive")) {
349 interactive++;361 interactive++;
350 continue;362 continue;
@@ -426,6 +438,7 @@ int main(int argc, char **argv) · 75 unmodified lines
426 if (bignum_ext || load_jscalc) {438 if (bignum_ext || load_jscalc) {
427 JS_AddIntrinsicBigFloat(ctx);439 JS_AddIntrinsicBigFloat(ctx);
428 JS_AddIntrinsicBigDecimal(ctx);440 JS_AddIntrinsicBigDecimal(ctx);
441 JS_AddIntrinsicOperators(ctx);
429 JS_EnableBignumExt(ctx, TRUE);442 JS_EnableBignumExt(ctx, TRUE);
430 }443 }
431#endif444#endif
@@ -459,6 +472,11 @@ int main(int argc, char **argv) · 27 unmodified lines
459 eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);472 eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
460 }473 }
461 474
475 for(i = 0; i < include_count; i++) {
476 if (eval_file(ctx, include_list[i], module))
477 goto fail;
478 }
479
462 if (expr) {480 if (expr) {
463 if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))481 if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))
464 goto fail;482 goto fail;
qjsc.c+16−8
@@ -36,9 +36,6 @@ · 35 unmodified lines
36#include "cutils.h"36#include "cutils.h"
37#include "quickjs-libc.h"37#include "quickjs-libc.h"
38 38
39/* enable bignums */
40#define CONFIG_BIGNUM
41
42typedef struct {39typedef struct {
43 char *name;40 char *name;
44 char *short_name;41 char *short_name;
@@ -79,7 +76,9 @@ static const FeatureEntry feature_list[] = { · 34 unmodified lines
79 { "promise", "Promise" },76 { "promise", "Promise" },
80#define FE_MODULE_LOADER 977#define FE_MODULE_LOADER 9
81 { "module-loader", NULL },78 { "module-loader", NULL },
79#ifdef CONFIG_BIGNUM
82 { "bigint", "BigInt" },80 { "bigint", "BigInt" },
81#endif
83};82};
84 83
85void namelist_add(namelist_t *lp, const char *name, const char *short_name,84void namelist_add(namelist_t *lp, const char *name, const char *short_name,
@@ -485,9 +484,12 @@ int main(int argc, char **argv) · 399 unmodified lines
485 FILE *fo;484 FILE *fo;
486 JSRuntime *rt;485 JSRuntime *rt;
487 JSContext *ctx;486 JSContext *ctx;
488 BOOL use_lto, bignum_ext;487 BOOL use_lto;
489 int module;488 int module;
490 OutputTypeEnum output_type;489 OutputTypeEnum output_type;
490#ifdef CONFIG_BIGNUM
491 BOOL bignum_ext = FALSE;
492#endif
491 493
492 out_filename = NULL;494 out_filename = NULL;
493 output_type = OUTPUT_EXECUTABLE;495 output_type = OUTPUT_EXECUTABLE;
@@ -497,7 +499,6 @@ int main(int argc, char **argv) · 3 unmodified lines
497 byte_swap = FALSE;499 byte_swap = FALSE;
498 verbose = 0;500 verbose = 0;
499 use_lto = FALSE;501 use_lto = FALSE;
500 bignum_ext = FALSE;
501 502
502 /* add system modules */503 /* add system modules */
503 namelist_add(&cmodule_list, "std", "std", 0);504 namelist_add(&cmodule_list, "std", "std", 0);
@@ -538,9 +539,13 @@ int main(int argc, char **argv) · 34 unmodified lines
538 }539 }
539 if (i == countof(feature_list))540 if (i == countof(feature_list))
540 goto bad_feature;541 goto bad_feature;
541 } else if (!strcmp(optarg, "bignum")) {542 } else
543#ifdef CONFIG_BIGNUM
544 if (!strcmp(optarg, "bignum")) {
542 bignum_ext = TRUE;545 bignum_ext = TRUE;
543 } else {546 } else
547#endif
548 {
544 bad_feature:549 bad_feature:
545 fprintf(stderr, "unsupported feature: %s\n", optarg);550 fprintf(stderr, "unsupported feature: %s\n", optarg);
546 exit(1);551 exit(1);
@@ -615,6 +620,7 @@ int main(int argc, char **argv) · 68 unmodified lines
615 if (bignum_ext) {620 if (bignum_ext) {
616 JS_AddIntrinsicBigFloat(ctx);621 JS_AddIntrinsicBigFloat(ctx);
617 JS_AddIntrinsicBigDecimal(ctx);622 JS_AddIntrinsicBigDecimal(ctx);
623 JS_AddIntrinsicOperators(ctx);
618 JS_EnableBignumExt(ctx, TRUE);624 JS_EnableBignumExt(ctx, TRUE);
619 }625 }
620#endif626#endif
@@ -661,13 +667,15 @@ int main(int argc, char **argv) · 40 unmodified lines
661 feature_list[i].init_name);667 feature_list[i].init_name);
662 }668 }
663 }669 }
670#ifdef CONFIG_BIGNUM
664 if (bignum_ext) {671 if (bignum_ext) {
665 fprintf(fo,672 fprintf(fo,
666 " JS_AddIntrinsicBigFloat(ctx);\n"673 " JS_AddIntrinsicBigFloat(ctx);\n"
667 " JS_AddIntrinsicBigDecimal(ctx);\n"674 " JS_AddIntrinsicBigDecimal(ctx);\n"
675 " JS_AddIntrinsicOperators(ctx);\n"
668 " JS_EnableBignumExt(ctx, 1);\n");676 " JS_EnableBignumExt(ctx, 1);\n");
669 }677 }
670 678#endif
671 fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");679 fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
672 680
673 for(i = 0; i < init_module_list.count; i++) {681 for(i = 0; i < init_module_list.count; i++) {
qjscalc.js+817−618
@@ -1,7 +1,7 @@
1/*1/*
2 * QuickJS Javascript Calculator2 * QuickJS Javascript Calculator
3 * 3 *
4 * Copyright (c) 2017-2018 Fabrice Bellard4 * Copyright (c) 2017-2020 Fabrice Bellard
5 *5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal7 * of this software and associated documentation files (the "Software"), to deal
@@ -27,20 +27,8 @@ · 19 unmodified lines
27var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix;27var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix;
28 28
29(function(global) {29(function(global) {
30 /* the types index are used to dispatch the operator functions */
31 var OT_INT = 0;
32 var OT_FRACTION = 10;
33 var OT_FLOAT64 = 19;
34 var OT_FLOAT = 20;
35 var OT_COMPLEX = 30;
36 var OT_MOD = 40;
37 var OT_POLY = 50;
38 var OT_POLYMOD = 55;
39 var OT_RFUNC = 60;
40 var OT_SERIES = 70;
41 var OT_ARRAY = 80;
42
43 global.Integer = global.BigInt;30 global.Integer = global.BigInt;
31 global.Float = global.BigFloat;
44 global.algebraicMode = true;32 global.algebraicMode = true;
45 33
46 /* add non enumerable properties */34 /* add non enumerable properties */
@@ -63,6 +51,42 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 16 unmodified lines
63 Object.defineProperty(obj, prop, desc);51 Object.defineProperty(obj, prop, desc);
64 }52 }
65 }53 }
54
55 /* same as proto[Symbol.operatorSet] = Operators.create(..op_list)
56 but allow shortcuts: left: [], right: [] or both
57 */
58 function operators_set(proto, ...op_list)
59 {
60 var new_op_list, i, a, j, b, k, obj, tab;
61 var fields = [ "left", "right" ];
62 new_op_list = [];
63 for(i = 0; i < op_list.length; i++) {
64 a = op_list[i];
65 if (a.left || a.right) {
66 tab = [ a.left, a.right ];
67 delete a.left;
68 delete a.right;
69 for(k = 0; k < 2; k++) {
70 obj = tab[k];
71 if (obj) {
72 if (!Array.isArray(obj)) {
73 obj = [ obj ];
74 }
75 for(j = 0; j < obj.length; j++) {
76 b = {};
77 Object.assign(b, a);
78 b[fields[k]] = obj[j];
79 new_op_list.push(b);
80 }
81 }
82 }
83 } else {
84 new_op_list.push(a);
85 }
86 }
87 proto[Symbol.operatorSet] =
88 Operators.create.call(null, ...new_op_list);
89 }
66 90
67 /* Integer */91 /* Integer */
68 92
@@ -104,11 +128,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 35 unmodified lines
104 var d, r, s, i, j, a;128 var d, r, s, i, j, a;
105 d = n - 1;129 d = n - 1;
106 s = 0;130 s = 0;
107 while (d & 1) {131 while ((d & 1) == 0) {
108 d >>= 1;132 d >>= 1;
109 s++;133 s++;
110 }134 }
111 t = Math.min(t, small_primes.length);135 if (small_primes.length < t)
136 t = small_primes.length;
112 loop: for(j = 0; j < t; j++) {137 loop: for(j = 0; j < t; j++) {
113 a = small_primes[j];138 a = small_primes[j];
114 r = Integer.pmod(a, d, n);139 r = Integer.pmod(a, d, n);
@@ -140,25 +165,31 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 25 unmodified lines
140 return fact_rec(a, i) * fact_rec(i + 1, b);165 return fact_rec(a, i) * fact_rec(i + 1, b);
141 }166 }
142 }167 }
143 168
169 /* math mode specific quirk to overload the integer division and power */
170 Operators.updateBigIntOperators(
171 {
172 "/"(a, b) {
173 if (algebraicMode) {
174 return Fraction.toFraction(a, b);
175 } else {
176 return Float(a) / Float(b);
177 }
178 },
179 "**"(a, b) {
180 if (algebraicMode) {
181 return generic_pow(a, b);
182 } else {
183 return Float(a) ** Float(b);
184 }
185 }
186 });
187
144 add_props(Integer, {188 add_props(Integer, {
145 isInteger(a) {189 isInteger(a) {
146 return typeof a === "bigint";190 /* integers are represented either as bigint or as number */
147 },191 return typeof a === "bigint" ||
148 [Symbol.operatorOrder]: OT_INT,192 (typeof a === "number" && Number.isSafeInteger(a));
149 [Symbol.operatorDiv](a, b) {
150 if (algebraicMode) {
151 return Fraction.toFraction(a, b);
152 } else {
153 return Float(a) / Float(b);
154 }
155 },
156 [Symbol.operatorPow](a, b) {
157 if (algebraicMode) {
158 return generic_pow(a, b);
159 } else {
160 return Float(a) ** Float(b);
161 }
162 },193 },
163 gcd(a, b) {194 gcd(a, b) {
164 var r;195 var r;
@@ -311,7 +342,10 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 146 unmodified lines
311 return this * this;342 return this * this;
312 },343 },
313 abs() {344 abs() {
314 return Math.abs(this);345 var v = this;
346 if (v < 0)
347 v = -v;
348 return v;
315 },349 },
316 conj() {350 conj() {
317 return this;351 return this;
@@ -373,8 +407,119 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 55 unmodified lines
373 return obj;407 return obj;
374 }408 }
375 409
410 function fraction_add(a, b) {
411 a = Fraction(a);
412 b = Fraction(b);
413 return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den);
414 }
415 function fraction_sub(a, b) {
416 a = Fraction(a);
417 b = Fraction(b);
418 return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den);
419 }
420 function fraction_mul(a, b) {
421 a = Fraction(a);
422 b = Fraction(b);
423 return Fraction.toFraction(a.num * b.num, a.den * b.den);
424 }
425 function fraction_div(a, b) {
426 a = Fraction(a);
427 b = Fraction(b);
428 return Fraction.toFraction(a.num * b.den, a.den * b.num);
429 }
430 function fraction_mod(a, b) {
431 var a1 = Fraction(a);
432 var b1 = Fraction(b);
433 return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b;
434 }
435 function fraction_eq(a, b) {
436 a = Fraction(a);
437 b = Fraction(b);
438 /* we assume the fractions are normalized */
439 return (a.num == b.num && a.den == b.den);
440 }
441 function fraction_lt(a, b) {
442 a = Fraction(a);
443 b = Fraction(b);
444 return (a.num * b.den < b.num * a.den);
445 }
446
447 /* operators are needed for fractions */
448 function float_add(a, b) {
449 return Float(a) + Float(b);
450 }
451 function float_sub(a, b) {
452 return Float(a) - Float(b);
453 }
454 function float_mul(a, b) {
455 return Float(a) * Float(b);
456 }
457 function float_div(a, b) {
458 return Float(a) / Float(b);
459 }
460 function float_mod(a, b) {
461 return Float(a) % Float(b);
462 }
463 function float_pow(a, b) {
464 return Float(a) ** Float(b);
465 }
466 function float_eq(a, b) {
467 /* XXX: may be better to use infinite precision for the comparison */
468 return Float(a) === Float(b);
469 }
470 function float_lt(a, b) {
471 a = Float(a);
472 b = Float(b);
473 /* XXX: may be better to use infinite precision for the comparison */
474 if (Float.isNaN(a) || Float.isNaN(b))
475 return undefined;
476 else
477 return a < b;
478 }
479
480 operators_set(Fraction.prototype,
481 {
482 "+": fraction_add,
483 "-": fraction_sub,
484 "*": fraction_mul,
485 "/": fraction_div,
486 "%": fraction_mod,
487 "**": generic_pow,
488 "==": fraction_eq,
489 "<": fraction_lt,
490 "pos"(a) {
491 return a;
492 },
493 "neg"(a) {
494 return Fraction(-a.num, a.den);
495 },
496 },
497 {
498 left: [Number, BigInt],
499 right: [Number, BigInt],
500 "+": fraction_add,
501 "-": fraction_sub,
502 "*": fraction_mul,
503 "/": fraction_div,
504 "%": fraction_mod,
505 "**": generic_pow,
506 "==": fraction_eq,
507 "<": fraction_lt,
508 },
509 {
510 left: Float,
511 right: Float,
512 "+": float_add,
513 "-": float_sub,
514 "*": float_mul,
515 "/": float_div,
516 "%": float_mod,
517 "**": float_pow,
518 "==": float_eq,
519 "<": float_lt,
520 });
521
376 add_props(Fraction, {522 add_props(Fraction, {
377 [Symbol.operatorOrder]: OT_FRACTION,
378 /* (internal use) simplify 'a' to an integer when possible */523 /* (internal use) simplify 'a' to an integer when possible */
379 toFraction(a, b) {524 toFraction(a, b) {
380 var r = Fraction(a, b);525 var r = Fraction(a, b);
@@ -383,72 +528,16 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 2 unmodified lines
383 else528 else
384 return r;529 return r;
385 },530 },
386
387 [Symbol.operatorAdd](a, b) {
388 a = Fraction(a);
389 b = Fraction(b);
390 return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den);
391 },
392 [Symbol.operatorSub](a, b) {
393 a = Fraction(a);
394 b = Fraction(b);
395 return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den);
396 },
397 [Symbol.operatorMul](a, b) {
398 a = Fraction(a);
399 b = Fraction(b);
400 return Fraction.toFraction(a.num * b.num, a.den * b.den);
401 },
402 [Symbol.operatorDiv](a, b) {
403 a = Fraction(a);
404 b = Fraction(b);
405 return Fraction.toFraction(a.num * b.den, a.den * b.num);
406 },
407 [Symbol.operatorMathMod](a, b) {
408 var a1 = Fraction(a);
409 var b1 = Fraction(b);
410 return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b;
411 },
412 [Symbol.operatorMod](a, b) {
413 var a1 = Fraction(a);
414 var b1 = Fraction(b);
415 return a - Integer.tdiv(a1.num * b1.den, a1.den * b1.num) * b;
416 },
417 [Symbol.operatorPow]: generic_pow,
418 [Symbol.operatorCmpEQ](a, b) {
419 a = Fraction(a);
420 b = Fraction(b);
421 /* we assume the fractions are normalized */
422 return (a.num == b.num && a.den == b.den);
423 },
424 [Symbol.operatorCmpLT](a, b) {
425 a = Fraction(a);
426 b = Fraction(b);
427 return (a.num * b.den < b.num * a.den);
428 },
429 [Symbol.operatorCmpLE](a, b) {
430 a = Fraction(a);
431 b = Fraction(b);
432 return (a.num * b.den <= b.num * a.den);
433 },
434 });531 });
435 532
436 add_props(Fraction.prototype, {533 add_props(Fraction.prototype, {
437 [Symbol.toPrimitive](hint) {534 [Symbol.toPrimitive](hint) {
438 if (hint === "integer") {535 if (hint === "string") {
439 return Integer.tdiv(this.num, this.den);
440 } else if (hint === "string") {
441 return this.toString();536 return this.toString();
442 } else {537 } else {
443 return Float(this.num) / this.den;538 return Float(this.num) / this.den;
444 }539 }
445 },540 },
446 [Symbol.operatorPlus]() {
447 return this;
448 },
449 [Symbol.operatorNeg]() {
450 return Fraction(-this.num, this.den);
451 },
452 inverse() {541 inverse() {
453 return Fraction(this.den, this.num);542 return Fraction(this.den, this.num);
454 },543 },
@@ -460,7 +549,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 5 unmodified lines
460 },549 },
461 abs() {550 abs() {
462 if (this.num < 0)551 if (this.num < 0)
463 return this[Symbol.operatorNeg]();552 return -this;
464 else553 else
465 return this;554 return this;
466 },555 },
@@ -483,29 +572,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 16 unmodified lines
483 572
484 /* Number (Float64) */573 /* Number (Float64) */
485 574
486 add_props(Number, {
487 [Symbol.operatorOrder]: OT_FLOAT64,
488 /* operators are needed for fractions */
489 [Symbol.operatorAdd](a, b) {
490 return Number(a) + Number(b);
491 },
492 [Symbol.operatorSub](a, b) {
493 return Number(a) - Number(b);
494 },
495 [Symbol.operatorMul](a, b) {
496 return Number(a) * Number(b);
497 },
498 [Symbol.operatorDiv](a, b) {
499 return Number(a) / Number(b);
500 },
501 [Symbol.operatorPow](a, b) {
502 return Number(a) ** Number(b);
503 },
504 });
505
506 add_props(Number.prototype, {575 add_props(Number.prototype, {
507 inverse() {576 inverse() {
508 return 1.0 / this;577 return 1 / this;
509 },578 },
510 norm2() {579 norm2() {
511 return this * this;580 return this * this;
@@ -536,8 +605,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 24 unmodified lines
536 605
537 /* Float */606 /* Float */
538 607
539 global.Float = global.BigFloat;
540
541 var const_tab = [];608 var const_tab = [];
542 609
543 /* we cache the constants for small precisions */610 /* we cache the constants for small precisions */
@@ -603,26 +670,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 59 unmodified lines
603 get SQRT2() { return get_const(7); },670 get SQRT2() { return get_const(7); },
604 });671 });
605 672
606 add_props(Float, {
607 [Symbol.operatorOrder]: OT_FLOAT,
608 /* operators are needed for fractions */
609 [Symbol.operatorAdd](a, b) {
610 return Float(a) + Float(b);
611 },
612 [Symbol.operatorSub](a, b) {
613 return Float(a) - Float(b);
614 },
615 [Symbol.operatorMul](a, b) {
616 return Float(a) * Float(b);
617 },
618 [Symbol.operatorDiv](a, b) {
619 return Float(a) / Float(b);
620 },
621 [Symbol.operatorPow](a, b) {
622 return Float(a) ** Float(b);
623 },
624 });
625
626 add_props(Float.prototype, {673 add_props(Float.prototype, {
627 inverse() {674 inverse() {
628 return 1.0 / this;675 return 1.0 / this;
@@ -631,7 +678,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 2 unmodified lines
631 return this * this;678 return this * this;
632 },679 },
633 abs() {680 abs() {
634 return Math.abs(this);681 return Float.abs(this);
635 },682 },
636 conj() {683 conj() {
637 return this;684 return this;
@@ -672,8 +719,61 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 34 unmodified lines
672 return obj;719 return obj;
673 }720 }
674 721
722
723 function complex_add(a, b) {
724 a = Complex(a);
725 b = Complex(b);
726 return Complex.toComplex(a.re + b.re, a.im + b.im);
727 }
728 function complex_sub(a, b) {
729 a = Complex(a);
730 b = Complex(b);
731 return Complex.toComplex(a.re - b.re, a.im - b.im);
732 }
733 function complex_mul(a, b) {
734 a = Complex(a);
735 b = Complex(b);
736 return Complex.toComplex(a.re * b.re - a.im * b.im,
737 a.re * b.im + a.im * b.re);
738 }
739 function complex_div(a, b) {
740 a = Complex(a);
741 b = Complex(b);
742 return a * b.inverse();
743 }
744 function complex_eq(a, b) {
745 a = Complex(a);
746 b = Complex(b);
747 return a.re == b.re && a.im == b.im;
748 }
749
750 operators_set(Complex.prototype,
751 {
752 "+": complex_add,
753 "-": complex_sub,
754 "*": complex_mul,
755 "/": complex_div,
756 "**": generic_pow,
757 "==": complex_eq,
758 "pos"(a) {
759 return a;
760 },
761 "neg"(a) {
762 return Complex(-a.re, -a.im);
763 }
764 },
765 {
766 left: [Number, BigInt, Float, Fraction],
767 right: [Number, BigInt, Float, Fraction],
768 "+": complex_add,
769 "-": complex_sub,
770 "*": complex_mul,
771 "/": complex_div,
772 "**": generic_pow,
773 "==": complex_eq,
774 });
775
675 add_props(Complex, {776 add_props(Complex, {
676 [Symbol.operatorOrder]: OT_COMPLEX,
677 /* simplify to real number when possible */777 /* simplify to real number when possible */
678 toComplex(re, im) {778 toComplex(re, im) {
679 if (algebraicMode && im == 0)779 if (algebraicMode && im == 0)
@@ -681,43 +781,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 1 unmodified line
681 else781 else
682 return Complex(re, im);782 return Complex(re, im);
683 },783 },
684
685 [Symbol.operatorAdd](a, b) {
686 a = Complex(a);
687 b = Complex(b);
688 return Complex.toComplex(a.re + b.re, a.im + b.im);
689 },
690 [Symbol.operatorSub](a, b) {
691 a = Complex(a);
692 b = Complex(b);
693 return Complex.toComplex(a.re - b.re, a.im - b.im);
694 },
695 [Symbol.operatorMul](a, b) {
696 a = Complex(a);
697 b = Complex(b);
698 return Complex.toComplex(a.re * b.re - a.im * b.im,
699 a.re * b.im + a.im * b.re);
700 },
701 [Symbol.operatorDiv](a, b) {
702 a = Complex(a);
703 b = Complex(b);
704 return a * b.inverse();
705 },
706 [Symbol.operatorPow]: generic_pow,
707 [Symbol.operatorCmpEQ](a, b) {
708 a = Complex(a);
709 b = Complex(b);
710 return a.re == b.re && a.im == b.im;
711 }
712 });784 });
713 785
714 add_props(Complex.prototype, {786 add_props(Complex.prototype, {
715 [Symbol.operatorPlus]() {
716 return this;
717 },
718 [Symbol.operatorNeg]() {
719 return Complex(-this.re, -this.im);
720 },
721 inverse() {787 inverse() {
722 var c = this.norm2();788 var c = this.norm2();
723 return Complex(this.re / c, -this.im / c);789 return Complex(this.re / c, -this.im / c);
@@ -785,14 +851,75 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 61 unmodified lines
785 obj.mod = m;851 obj.mod = m;
786 return obj;852 return obj;
787 };853 };
854
855 function mod_add(a, b) {
856 if (!(a instanceof Mod)) {
857 return Mod(a + b.res, b.mod);
858 } else if (!(b instanceof Mod)) {
859 return Mod(a.res + b, a.mod);
860 } else {
861 if (a.mod != b.mod)
862 throw TypeError("different modulo for binary operator");
863 return Mod(a.res + b.res, a.mod);
864 }
865 }
866 function mod_sub(a, b) {
867 if (!(a instanceof Mod)) {
868 return Mod(a - b.res, b.mod);
869 } else if (!(b instanceof Mod)) {
870 return Mod(a.res - b, a.mod);
871 } else {
872 if (a.mod != b.mod)
873 throw TypeError("different modulo for binary operator");
874 return Mod(a.res - b.res, a.mod);
875 }
876 }
877 function mod_mul(a, b) {
878 if (!(a instanceof Mod)) {
879 return Mod(a * b.res, b.mod);
880 } else if (!(b instanceof Mod)) {
881 return Mod(a.res * b, a.mod);
882 } else {
883 if (a.mod != b.mod)
884 throw TypeError("different modulo for binary operator");
885 return Mod(a.res * b.res, a.mod);
886 }
887 }
888 function mod_div(a, b) {
889 if (!(b instanceof Mod))
890 b = Mod(b, a.mod);
891 return mod_mul(a, b.inverse());
892 }
893 function mod_eq(a, b) {
894 return (a.mod == b.mod && a.res == b.res);
895 }
788 896
789 add_props(Mod.prototype, {897 operators_set(Mod.prototype,
790 [Symbol.operatorPlus]() {898 {
791 return this;899 "+": mod_add,
792 },900 "-": mod_sub,
793 [Symbol.operatorNeg]() {901 "*": mod_mul,
794 return Mod(-this.res, this.mod);902 "/": mod_div,
903 "**": generic_pow,
904 "==": mod_eq,
905 "pos"(a) {
906 return a;
907 },
908 "neg"(a) {
909 return Mod(-a.res, a.mod);
910 }
795 },911 },
912 {
913 left: [Number, BigInt, Float, Fraction],
914 right: [Number, BigInt, Float, Fraction],
915 "+": mod_add,
916 "-": mod_sub,
917 "*": mod_mul,
918 "/": mod_div,
919 "**": generic_pow,
920 });
921
922 add_props(Mod.prototype, {
796 inverse() {923 inverse() {
797 var a = this, m = a.mod;924 var a = this, m = a.mod;
798 if (Integer.isInteger(m)) {925 if (Integer.isInteger(m)) {
@@ -806,57 +933,21 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
806 },933 },
807 });934 });
808 935
809 add_props(Mod, {
810 [Symbol.operatorOrder]: OT_MOD,
811 [Symbol.operatorAdd](a, b) {
812 if (!(a instanceof Mod)) {
813 return Mod(a + b.res, b.mod);
814 } else if (!(b instanceof Mod)) {
815 return Mod(a.res + b, a.mod);
816 } else {
817 if (a.mod != b.mod)
818 throw TypeError("different modulo for binary operator");
819 return Mod(a.res + b.res, a.mod);
820 }
821 },
822 [Symbol.operatorSub](a, b) {
823 if (!(a instanceof Mod)) {
824 return Mod(a - b.res, b.mod);
825 } else if (!(b instanceof Mod)) {
826 return Mod(a.res - b, a.mod);
827 } else {
828 if (a.mod != b.mod)
829 throw TypeError("different modulo for binary operator");
830 return Mod(a.res - b.res, a.mod);
831 }
832 },
833 [Symbol.operatorMul](a, b) {
834 if (!(a instanceof Mod)) {
835 return Mod(a * b.res, b.mod);
836 } else if (!(b instanceof Mod)) {
837 return Mod(a.res * b, a.mod);
838 } else {
839 if (a.mod != b.mod)
840 throw TypeError("different modulo for binary operator");
841 return Mod(a.res * b.res, a.mod);
842 }
843 },
844 [Symbol.operatorDiv](a, b) {
845 if (!(b instanceof Mod))
846 b = Mod(b, a.mod);
847 return Mod[Symbol.operatorMul](a, b.inverse());
848 },
849 [Symbol.operatorPow]: generic_pow,
850 [Symbol.operatorCmpEQ](a, b) {
851 if (!(a instanceof Mod) ||
852 !(b instanceof Mod))
853 return false;
854 return (a.mod == b.mod && a.res == b.res);
855 }
856 });
857
858 /* Polynomial */936 /* Polynomial */
859 937
938 function polynomial_is_scalar(a)
939 {
940 if (typeof a === "number" ||
941 typeof a === "bigint" ||
942 typeof a === "bigfloat")
943 return true;
944 if (a instanceof Fraction ||
945 a instanceof Complex ||
946 a instanceof Mod)
947 return true;
948 return false;
949 }
950
860 Polynomial = function Polynomial(a)951 Polynomial = function Polynomial(a)
861 {952 {
862 if (new.target)953 if (new.target)
@@ -868,7 +959,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 5 unmodified lines
868 a = [ 0 ];959 a = [ 0 ];
869 Object.setPrototypeOf(a, Polynomial.prototype);960 Object.setPrototypeOf(a, Polynomial.prototype);
870 return a.trim();961 return a.trim();
871 } else if (a.constructor[Symbol.operatorOrder] <= OT_MOD) {962 } else if (polynomial_is_scalar(a)) {
872 a = [a];963 a = [a];
873 Object.setPrototypeOf(a, Polynomial.prototype);964 Object.setPrototypeOf(a, Polynomial.prototype);
874 return a;965 return a;
@@ -1004,18 +1095,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 129 unmodified lines
1004 a.length = i;1095 a.length = i;
1005 return a;1096 return a;
1006 },1097 },
1007 [Symbol.operatorPlus]() {
1008 return this;
1009 },
1010 [Symbol.operatorNeg]() {
1011 var r, i, n, a;
1012 a = this;
1013 n = a.length;
1014 r = [];
1015 for(i = 0; i < n; i++)
1016 r[i] = -a[i];
1017 return Polynomial(r);
1018 },
1019 conj() {1098 conj() {
1020 var r, i, n, a;1099 var r, i, n, a;
1021 a = this;1100 a = this;
@@ -1097,74 +1176,106 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 75 unmodified lines
1097 },1176 },
1098 });1177 });
1099 1178
1100 add_props(Polynomial, {1179
1101 [Symbol.operatorOrder]: OT_POLY,1180 function polynomial_add(a, b) {
1102 [Symbol.operatorAdd](a, b) {1181 var tmp, r, i, n1, n2;
1103 var tmp, r, i, n1, n2;1182 a = Polynomial(a);
1104 a = Polynomial(a);1183 b = Polynomial(b);
1105 b = Polynomial(b);1184 if (a.length < b.length) {
1106 if (a.length < b.length) {1185 tmp = a;
1107 tmp = a;1186 a = b;
1108 a = b;1187 b = tmp;
1109 b = tmp;1188 }
1110 }1189 n1 = b.length;
1111 n1 = b.length;1190 n2 = a.length;
1112 n2 = a.length;1191 r = [];
1113 r = [];1192 for(i = 0; i < n1; i++)
1114 for(i = 0; i < n1; i++)1193 r[i] = a[i] + b[i];
1115 r[i] = a[i] + b[i];1194 for(i = n1; i < n2; i++)
1116 for(i = n1; i < n2; i++)1195 r[i] = a[i];
1117 r[i] = a[i];1196 return Polynomial(r);
1118 return Polynomial(r);1197 }
1119 },1198 function polynomial_sub(a, b) {
1120 [Symbol.operatorSub](a, b) {1199 return polynomial_add(a, -b);
1121 return Polynomial[Symbol.operatorAdd](a, -b);1200 }
1122 },1201 function polynomial_mul(a, b) {
1123 [Symbol.operatorMul](a, b) {1202 var i, j, n1, n2, n, r;
1124 var i, j, n1, n2, n, r;1203 a = Polynomial(a);
1125 a = Polynomial(a);1204 b = Polynomial(b);
1126 b = Polynomial(b);1205 n1 = a.length;
1127 n1 = a.length;1206 n2 = b.length;
1128 n2 = b.length;1207 n = n1 + n2 - 1;
1129 n = n1 + n2 - 1;1208 r = [];
1130 r = [];1209 for(i = 0; i < n; i++)
1131 for(i = 0; i < n; i++)1210 r[i] = 0;
1132 r[i] = 0;1211 for(i = 0; i < n1; i++) {
1133 for(i = 0; i < n1; i++) {1212 for(j = 0; j < n2; j++) {
1134 for(j = 0; j < n2; j++) {1213 r[i + j] += a[i] * b[j];
1135 r[i + j] += a[i] * b[j];
1136 }
1137 }1214 }
1138 return Polynomial(r);1215 }
1139 },1216 return Polynomial(r);
1140 [Symbol.operatorDiv](a, b) {1217 }
1141 if (b.constructor[Symbol.operatorOrder] <= OT_COMPLEX)1218 function polynomial_div_scalar(a, b) {
1142 return a * (1 / b);1219 return a * (1 / b);
1143 else1220 }
1144 return RationalFunction(Polynomial(a),1221 function polynomial_div(a, b)
1145 Polynomial(b));1222 {
1146 },1223 return RationalFunction(Polynomial(a),
1147 [Symbol.operatorPow]: generic_pow,1224 Polynomial(b));
1148 [Symbol.operatorMathMod](a, b) {1225 }
1149 return Polynomial.divrem(a, b)[1];1226 function polynomial_mod(a, b) {
1150 },1227 return Polynomial.divrem(a, b)[1];
1151 [Symbol.operatorMod](a, b) {1228 }
1152 return Polynomial.divrem(a, b)[1];1229 function polynomial_eq(a, b) {
1153 },1230 var n, i;
1154 [Symbol.operatorCmpEQ](a, b) {1231 n = a.length;
1155 var n, i;1232 if (n != b.length)
1156 if (!(a instanceof Polynomial) ||1233 return false;
1157 !(b instanceof Polynomial))1234 for(i = 0; i < n; i++) {
1158 return false;1235 if (a[i] != b[i])
1159 n = a.length;
1160 if (n != b.length)
1161 return false;1236 return false;
1162 for(i = 0; i < n; i++) {1237 }
1163 if (a[i] != b[i])1238 return true;
1164 return false;1239 }
1165 }1240
1166 return true;1241 operators_set(Polynomial.prototype,
1167 },1242 {
1243 "+": polynomial_add,
1244 "-": polynomial_sub,
1245 "*": polynomial_mul,
1246 "/": polynomial_div,
1247 "**": generic_pow,
1248 "==": polynomial_eq,
1249 "pos"(a) {
1250 return a;
1251 },
1252 "neg"(a) {
1253 var r, i, n, a;
1254 n = a.length;
1255 r = [];
1256 for(i = 0; i < n; i++)
1257 r[i] = -a[i];
1258 return Polynomial(r);
1259 },
1260 },
1261 {
1262 left: [Number, BigInt, Float, Fraction, Complex, Mod],
1263 "+": polynomial_add,
1264 "-": polynomial_sub,
1265 "*": polynomial_mul,
1266 "/": polynomial_div,
1267 "**": generic_pow, /* XXX: only for integer */
1268 },
1269 {
1270 right: [Number, BigInt, Float, Fraction, Complex, Mod],
1271 "+": polynomial_add,
1272 "-": polynomial_sub,
1273 "*": polynomial_mul,
1274 "/": polynomial_div_scalar,
1275 "**": generic_pow, /* XXX: only for integer */
1276 });
1277
1278 add_props(Polynomial, {
1168 divrem(a, b) {1279 divrem(a, b) {
1169 var n1, n2, i, j, q, r, n, c;1280 var n1, n2, i, j, q, r, n, c;
1170 if (b.deg() < 0)1281 if (b.deg() < 0)
@@ -1252,13 +1363,66 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 81 unmodified lines
1252 return obj;1363 return obj;
1253 };1364 };
1254 1365
1366 function polymod_add(a, b) {
1367 if (!(a instanceof PolyMod)) {
1368 return PolyMod(a + b.res, b.mod);
1369 } else if (!(b instanceof PolyMod)) {
1370 return PolyMod(a.res + b, a.mod);
1371 } else {
1372 if (a.mod != b.mod)
1373 throw TypeError("different modulo for binary operator");
1374 return PolyMod(a.res + b.res, a.mod);
1375 }
1376 }
1377 function polymod_sub(a, b) {
1378 return polymod_add(a, -b);
1379 }
1380 function polymod_mul(a, b) {
1381 if (!(a instanceof PolyMod)) {
1382 return PolyMod(a * b.res, b.mod);
1383 } else if (!(b instanceof PolyMod)) {
1384 return PolyMod(a.res * b, a.mod);
1385 } else {
1386 if (a.mod != b.mod)
1387 throw TypeError("different modulo for binary operator");
1388 return PolyMod(a.res * b.res, a.mod);
1389 }
1390 }
1391 function polymod_div(a, b) {
1392 if (!(b instanceof PolyMod))
1393 b = PolyMod(b, a.mod);
1394 return polymod_mul(a, b.inverse());
1395 }
1396 function polymod_eq(a, b) {
1397 return (a.mod == b.mod && a.res == b.res);
1398 }
1399
1400 operators_set(PolyMod.prototype,
1401 {
1402 "+": polymod_add,
1403 "-": polymod_sub,
1404 "*": polymod_mul,
1405 "/": polymod_div,
1406 "**": generic_pow,
1407 "==": polymod_eq,
1408 "pos"(a) {
1409 return a;
1410 },
1411 "neg"(a) {
1412 return PolyMod(-a.res, a.mod);
1413 },
1414 },
1415 {
1416 left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1417 right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1418 "+": polymod_add,
1419 "-": polymod_sub,
1420 "*": polymod_mul,
1421 "/": polymod_div,
1422 "**": generic_pow, /* XXX: only for integer */
1423 });
1424
1255 add_props(PolyMod.prototype, {1425 add_props(PolyMod.prototype, {
1256 [Symbol.operatorPlus]() {
1257 return this;
1258 },
1259 [Symbol.operatorNeg]() {
1260 return PolyMod(-this.res, this.mod);
1261 },
1262 inverse() {1426 inverse() {
1263 var a = this, m = a.mod;1427 var a = this, m = a.mod;
1264 if (m instanceof Polynomial) {1428 if (m instanceof Polynomial) {
@@ -1272,55 +1436,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
1272 },1436 },
1273 });1437 });
1274 1438
1275 add_props(PolyMod, {
1276 [Symbol.operatorOrder]: OT_POLYMOD,
1277 [Symbol.operatorAdd](a, b) {
1278 if (!(a instanceof PolyMod)) {
1279 return PolyMod(a + b.res, b.mod);
1280 } else if (!(b instanceof PolyMod)) {
1281 return PolyMod(a.res + b, a.mod);
1282 } else {
1283 if (a.mod != b.mod)
1284 throw TypeError("different modulo for binary operator");
1285 return PolyMod(a.res + b.res, a.mod);
1286 }
1287 },
1288 [Symbol.operatorSub](a, b) {
1289 if (!(a instanceof PolyMod)) {
1290 return PolyMod(a - b.res, b.mod);
1291 } else if (!(b instanceof PolyMod)) {
1292 return PolyMod(a.res - b, a.mod);
1293 } else {
1294 if (a.mod != b.mod)
1295 throw TypeError("different modulo for binary operator");
1296 return PolyMod(a.res - b.res, a.mod);
1297 }
1298 },
1299 [Symbol.operatorMul](a, b) {
1300 if (!(a instanceof PolyMod)) {
1301 return PolyMod(a * b.res, b.mod);
1302 } else if (!(b instanceof PolyMod)) {
1303 return PolyMod(a.res * b, a.mod);
1304 } else {
1305 if (a.mod != b.mod)
1306 throw TypeError("different modulo for binary operator");
1307 return PolyMod(a.res * b.res, a.mod);
1308 }
1309 },
1310 [Symbol.operatorDiv](a, b) {
1311 if (!(b instanceof PolyMod))
1312 b = PolyMod(b, a.mod);
1313 return PolyMod[Symbol.operatorMul](a, b.inverse());
1314 },
1315 [Symbol.operatorPow]: generic_pow,
1316 [Symbol.operatorCmpEQ](a, b) {
1317 if (!(a instanceof PolyMod) ||
1318 !(b instanceof PolyMod))
1319 return false;
1320 return (a.mod == b.mod && a.res == b.res);
1321 }
1322 });
1323
1324 /* Rational function */1439 /* Rational function */
1325 1440
1326 RationalFunction = function RationalFunction(a, b)1441 RationalFunction = function RationalFunction(a, b)
@@ -1347,12 +1462,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 20 unmodified lines
1347 }1462 }
1348 1463
1349 add_props(RationalFunction.prototype, {1464 add_props(RationalFunction.prototype, {
1350 [Symbol.operatorPlus]() {
1351 return this;
1352 },
1353 [Symbol.operatorNeg]() {
1354 return RationalFunction(-this.num, this.den);
1355 },
1356 inverse() {1465 inverse() {
1357 return RationalFunction(this.den, this.num);1466 return RationalFunction(this.den, this.num);
1358 },1467 },
@@ -1378,8 +1487,59 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 19 unmodified lines
1378 },1487 },
1379 });1488 });
1380 1489
1490 function ratfunc_add(a, b) {
1491 a = RationalFunction.toRationalFunction(a);
1492 b = RationalFunction.toRationalFunction(b);
1493 return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den);
1494 }
1495 function ratfunc_sub(a, b) {
1496 a = RationalFunction.toRationalFunction(a);
1497 b = RationalFunction.toRationalFunction(b);
1498 return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den);
1499 }
1500 function ratfunc_mul(a, b) {
1501 a = RationalFunction.toRationalFunction(a);
1502 b = RationalFunction.toRationalFunction(b);
1503 return RationalFunction(a.num * b.num, a.den * b.den);
1504 }
1505 function ratfunc_div(a, b) {
1506 a = RationalFunction.toRationalFunction(a);
1507 b = RationalFunction.toRationalFunction(b);
1508 return RationalFunction(a.num * b.den, a.den * b.num);
1509 }
1510 function ratfunc_eq(a, b) {
1511 a = RationalFunction.toRationalFunction(a);
1512 b = RationalFunction.toRationalFunction(b);
1513 /* we assume the fractions are normalized */
1514 return (a.num == b.num && a.den == b.den);
1515 }
1516
1517 operators_set(RationalFunction.prototype,
1518 {
1519 "+": ratfunc_add,
1520 "-": ratfunc_sub,
1521 "*": ratfunc_mul,
1522 "/": ratfunc_div,
1523 "**": generic_pow,
1524 "==": ratfunc_eq,
1525 "pos"(a) {
1526 return a;
1527 },
1528 "neg"(a) {
1529 return RationalFunction(-this.num, this.den);
1530 },
1531 },
1532 {
1533 left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1534 right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1535 "+": ratfunc_add,
1536 "-": ratfunc_sub,
1537 "*": ratfunc_mul,
1538 "/": ratfunc_div,
1539 "**": generic_pow, /* should only be used with integers */
1540 });
1541
1381 add_props(RationalFunction, {1542 add_props(RationalFunction, {
1382 [Symbol.operatorOrder]: OT_RFUNC,
1383 /* This function always return a RationalFunction object even1543 /* This function always return a RationalFunction object even
1384 if it could simplified to a polynomial, so it is not1544 if it could simplified to a polynomial, so it is not
1385 equivalent to RationalFunction(a) */1545 equivalent to RationalFunction(a) */
@@ -1394,33 +1554,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 8 unmodified lines
1394 return obj;1554 return obj;
1395 }1555 }
1396 },1556 },
1397 [Symbol.operatorAdd](a, b) {
1398 a = RationalFunction.toRationalFunction(a);
1399 b = RationalFunction.toRationalFunction(b);
1400 return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den);
1401 },
1402 [Symbol.operatorSub](a, b) {
1403 a = RationalFunction.toRationalFunction(a);
1404 b = RationalFunction.toRationalFunction(b);
1405 return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den);
1406 },
1407 [Symbol.operatorMul](a, b) {
1408 a = RationalFunction.toRationalFunction(a);
1409 b = RationalFunction.toRationalFunction(b);
1410 return RationalFunction(a.num * b.num, a.den * b.den);
1411 },
1412 [Symbol.operatorDiv](a, b) {
1413 a = RationalFunction.toRationalFunction(a);
1414 b = RationalFunction.toRationalFunction(b);
1415 return RationalFunction(a.num * b.den, a.den * b.num);
1416 },
1417 [Symbol.operatorPow]: generic_pow,
1418 [Symbol.operatorCmpEQ](a, b) {
1419 a = RationalFunction.toRationalFunction(a);
1420 b = RationalFunction.toRationalFunction(b);
1421 /* we assume the fractions are normalized */
1422 return (a.num == b.num && a.den == b.den);
1423 },
1424 });1557 });
1425 1558
1426 /* Power series */1559 /* Power series */
@@ -1435,6 +1568,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 8 unmodified lines
1435 }1568 }
1436 return n;1569 return n;
1437 };1570 };
1571
1572 function series_is_scalar_or_polynomial(a)
1573 {
1574 return polynomial_is_scalar(a) ||
1575 (a instanceof Polynomial);
1576 }
1438 1577
1439 /* n is the maximum number of terms if 'a' is not a serie */1578 /* n is the maximum number of terms if 'a' is not a serie */
1440 Series = function Series(a, n) {1579 Series = function Series(a, n) {
@@ -1442,7 +1581,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 1 unmodified line
1442 1581
1443 if (a instanceof Series) {1582 if (a instanceof Series) {
1444 return a;1583 return a;
1445 } else if (a.constructor[Symbol.operatorOrder] <= OT_POLY) {1584 } else if (series_is_scalar_or_polynomial(a)) {
1446 if (n <= 0) {1585 if (n <= 0) {
1447 /* XXX: should still use the polynomial degree */1586 /* XXX: should still use the polynomial degree */
1448 return Series.zero(0, 0);1587 return Series.zero(0, 0);
@@ -1462,19 +1601,132 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 13 unmodified lines
1462 }1601 }
1463 };1602 };
1464 1603
1465 add_props(Series.prototype, {1604 function series_add(v1, v2) {
1466 [Symbol.operatorPlus]() {1605 var tmp, d, emin, n, r, i, j, v2_emin, c1, c2;
1467 return this;1606 if (!(v1 instanceof Series)) {
1468 },1607 tmp = v1;
1469 [Symbol.operatorNeg]() {1608 v1 = v2;
1470 var obj, n, i;1609 v2 = tmp;
1471 n = this.length;1610 }
1472 obj = Series.zero(this.length, this.emin);1611 d = v1.emin + v1.length;
1473 for(i = 0; i < n; i++) {1612 if (series_is_scalar_or_polynomial(v2)) {
1474 obj[i] = -this[i];1613 v2 = Polynomial(v2);
1614 if (d <= 0)
1615 return v1;
1616 v2_emin = 0;
1617 } else if (v2 instanceof RationalFunction) {
1618 /* compute the emin of the rational fonction */
1619 i = get_emin(v2.num) - get_emin(v2.den);
1620 if (d <= i)
1621 return v1;
1622 /* compute the serie with the required terms */
1623 v2 = Series(v2, d - i);
1624 v2_emin = v2.emin;
1625 } else {
1626 v2_emin = v2.emin;
1627 d = Math.min(d, v2_emin + v2.length);
1628 }
1629 emin = Math.min(v1.emin, v2_emin);
1630 n = d - emin;
1631 r = Series.zero(n, emin);
1632 /* XXX: slow */
1633 for(i = emin; i < d; i++) {
1634 j = i - v1.emin;
1635 if (j >= 0 && j < v1.length)
1636 c1 = v1[j];
1637 else
1638 c1 = 0;
1639 j = i - v2_emin;
1640 if (j >= 0 && j < v2.length)
1641 c2 = v2[j];
1642 else
1643 c2 = 0;
1644 r[i - emin] = c1 + c2;
1645 }
1646 return r.trim();
1647 }
1648 function series_sub(a, b) {
1649 return series_add(a, -b);
1650 }
1651 function series_mul(v1, v2) {
1652 var n, i, j, r, n, emin, n1, n2, k;
1653 if (!(v1 instanceof Series))
1654 v1 = Series(v1, v2.length);
1655 else if (!(v2 instanceof Series))
1656 v2 = Series(v2, v1.length);
1657 emin = v1.emin + v2.emin;
1658 n = Math.min(v1.length, v2.length);
1659 n1 = v1.length;
1660 n2 = v2.length;
1661 r = Series.zero(n, emin);
1662 for(i = 0; i < n1; i++) {
1663 k = Math.min(n2, n - i);
1664 for(j = 0; j < k; j++) {
1665 r[i + j] += v1[i] * v2[j];
1475 }1666 }
1476 return obj;1667 }
1477 },1668 return r.trim();
1669 }
1670 function series_div(v1, v2) {
1671 if (!(v2 instanceof Series))
1672 v2 = Series(v2, v1.length);
1673 return series_mul(v1, v2.inverse());
1674 }
1675 function series_pow(a, b) {
1676 if (Integer.isInteger(b)) {
1677 return generic_pow(a, b);
1678 } else {
1679 if (!(a instanceof Series))
1680 a = Series(a, b.length);
1681 return exp(log(a) * b);
1682 }
1683 }
1684 function series_eq(a, b) {
1685 var n, i;
1686 if (a.emin != b.emin)
1687 return false;
1688 n = a.length;
1689 if (n != b.length)
1690 return false;
1691 for(i = 0; i < n; i++) {
1692 if (a[i] != b[i])
1693 return false;
1694 }
1695 return true;
1696 }
1697
1698 operators_set(Series.prototype,
1699 {
1700 "+": series_add,
1701 "-": series_sub,
1702 "*": series_mul,
1703 "/": series_div,
1704 "**": series_pow,
1705 "==": series_eq,
1706 "pos"(a) {
1707 return a;
1708 },
1709 "neg"(a) {
1710 var obj, n, i;
1711 n = a.length;
1712 obj = Series.zero(a.length, a.emin);
1713 for(i = 0; i < n; i++) {
1714 obj[i] = -a[i];
1715 }
1716 return obj;
1717 },
1718 },
1719 {
1720 left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1721 right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1722 "+": series_add,
1723 "-": series_sub,
1724 "*": series_mul,
1725 "/": series_div,
1726 "**": series_pow,
1727 });
1728
1729 add_props(Series.prototype, {
1478 conj() {1730 conj() {
1479 var obj, n, i;1731 var obj, n, i;
1480 n = this.length;1732 n = this.length;
@@ -1610,7 +1862,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 129 unmodified lines
1610 });1862 });
1611 1863
1612 add_props(Series, {1864 add_props(Series, {
1613 [Symbol.operatorOrder]: OT_SERIES,
1614 /* new series of length n and first exponent emin */1865 /* new series of length n and first exponent emin */
1615 zero(n, emin) {1866 zero(n, emin) {
1616 var r, i, obj;1867 var r, i, obj;
@@ -1624,108 +1875,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
1624 Object.setPrototypeOf(r, obj);1875 Object.setPrototypeOf(r, obj);
1625 return r;1876 return r;
1626 },1877 },
1627 [Symbol.operatorAdd](v1, v2) {
1628 var tmp, d, emin, n, r, i, j, v2_emin, c1, c2;
1629 if (!(v1 instanceof Series)) {
1630 tmp = v1;
1631 v1 = v2;
1632 v2 = tmp;
1633 }
1634 d = v1.emin + v1.length;
1635 if (v2.constructor[Symbol.operatorOrder] <= OT_POLY) {
1636 v2 = Polynomial(v2);
1637 if (d <= 0)
1638 return v1;
1639 v2_emin = 0;
1640 } else if (v2 instanceof RationalFunction) {
1641 /* compute the emin of the rational fonction */
1642 i = get_emin(v2.num) - get_emin(v2.den);
1643 if (d <= i)
1644 return v1;
1645 /* compute the serie with the required terms */
1646 v2 = Series(v2, d - i);
1647 v2_emin = v2.emin;
1648 } else {
1649 v2_emin = v2.emin;
1650 d = Math.min(d, v2_emin + v2.length);
1651 }
1652 emin = Math.min(v1.emin, v2_emin);
1653 n = d - emin;
1654 r = Series.zero(n, emin);
1655 /* XXX: slow */
1656 for(i = emin; i < d; i++) {
1657 j = i - v1.emin;
1658 if (j >= 0 && j < v1.length)
1659 c1 = v1[j];
1660 else
1661 c1 = 0;
1662 j = i - v2_emin;
1663 if (j >= 0 && j < v2.length)
1664 c2 = v2[j];
1665 else
1666 c2 = 0;
1667 r[i - emin] = c1 + c2;
1668 }
1669 return r.trim();
1670 },
1671 [Symbol.operatorSub](a, b) {
1672 return Series[Symbol.operatorAdd](a, -b);
1673 },
1674 [Symbol.operatorMul](v1, v2) {
1675 var n, i, j, r, n, emin, n1, n2, k;
1676 if (!(v1 instanceof Series))
1677 v1 = Series(v1, v2.length);
1678 else if (!(v2 instanceof Series))
1679 v2 = Series(v2, v1.length);
1680 emin = v1.emin + v2.emin;
1681 n = Math.min(v1.length, v2.length);
1682 n1 = v1.length;
1683 n2 = v2.length;
1684 r = Series.zero(n, emin);
1685 for(i = 0; i < n1; i++) {
1686 k = Math.min(n2, n - i);
1687 for(j = 0; j < k; j++) {
1688 r[i + j] += v1[i] * v2[j];
1689 }
1690 }
1691 return r.trim();
1692 },
1693 [Symbol.operatorDiv](v1, v2) {
1694 if (!(v2 instanceof Series))
1695 v2 = Series(v2, v1.length);
1696 return Series[Symbol.operatorMul](v1, v2.inverse());
1697 },
1698 [Symbol.operatorPow](a, b) {
1699 if (Integer.isInteger(b)) {
1700 return generic_pow(a, b);
1701 } else {
1702 if (!(a instanceof Series))
1703 a = Series(a, b.length);
1704 return exp(log(a) * b);
1705 }
1706 },
1707 [Symbol.operatorCmpEQ](a, b) {
1708 var n, i;
1709 if (!(a instanceof Series) ||
1710 !(b instanceof Series))
1711 return false;
1712 if (a.emin != b.emin)
1713 return false;
1714 n = a.length;
1715 if (n != b.length)
1716 return false;
1717 for(i = 0; i < n; i++) {
1718 if (a[i] != b[i])
1719 return false;
1720 }
1721 return true;
1722 },
1723 O(a) {1878 O(a) {
1724 function ErrorO() {1879 function ErrorO() {
1725 return TypeError("invalid O() argument");1880 return TypeError("invalid O() argument");
1726 }1881 }
1727 var n;1882 var n;
1728 if (a.constructor[Symbol.operatorOrder] <= OT_POLY) {1883 if (series_is_scalar_or_polynomial(a)) {
1729 a = Polynomial(a);1884 a = Polynomial(a);
1730 n = a.deg();1885 n = a.deg();
1731 if (n < 0)1886 if (n < 0)
@@ -2061,130 +2216,138 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 329 unmodified lines
2061 },2216 },
2062 });2217 });
2063 2218
2064 add_props(Array, {2219 function array_add(a, b) {
2065 [Symbol.operatorOrder]: OT_ARRAY,2220 var r, i, n;
2066 [Symbol.operatorAdd](a, b) {2221 n = a.length;
2067 var r, i, n;2222 if (n != b.length)
2068 if (!Array.isArray(a) || !Array.isArray(b))2223 throw TypeError("incompatible array size");
2069 throw TypeError("array expected");2224 r = [];
2070 n = a.length;2225 for(i = 0; i < n; i++)
2071 if (n != b.length)2226 r[i] = a[i] + b[i];
2072 throw TypeError("incompatible array size");2227 return r;
2073 r = [];2228 }
2074 for(i = 0; i < n; i++)2229 function array_sub(a, b) {
2075 r[i] = a[i] + b[i];2230 var r, i, n;
2076 return r;2231 n = a.length;
2077 },2232 if (n != b.length)
2078 [Symbol.operatorSub](a, b) {2233 throw TypeError("incompatible array size");
2079 var r, i, n;2234 r = [];
2080 n = a.length;2235 for(i = 0; i < n; i++)
2081 if (!Array.isArray(a) || !Array.isArray(b))2236 r[i] = a[i] - b[i];
2082 throw TypeError("array expected");2237 return r;
2083 if (n != b.length)2238 }
2084 throw TypeError("incompatible array size");2239 function array_scalar_mul(a, b) {
2085 r = [];2240 var r, i, n;
2086 for(i = 0; i < n; i++)2241 n = a.length;
2087 r[i] = a[i] - b[i];2242 r = [];
2088 return r;2243 for(i = 0; i < n; i++)
2089 },2244 r[i] = a[i] * b;
2090 scalar_mul(a, b) {2245 return r;
2091 var r, i, n;2246 }
2092 n = a.length;2247 function array_mul(a, b) {
2093 r = [];2248 var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat;
2094 for(i = 0; i < n; i++)2249 h = a.length;
2095 r[i] = a[i] * b;2250 a_mat = Array.isArray(a[0]);
2096 return r;2251 if (a_mat) {
2097 },2252 l = a[0].length;
2098 [Symbol.operatorMul](a, b) {2253 } else {
2099 var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat, a_is_array, b_is_array;2254 l = 1;
2100 a_is_array = Array.isArray(a);2255 }
2101 b_is_array = Array.isArray(b);2256 if (l != b.length)
2102 if (!a_is_array && !b_is_array) {2257 throw RangeError("incompatible matrix size");
2103 throw TypeError("array expected");2258 b_mat = Array.isArray(b[0]);
2104 } else if (!a_is_array && b_is_array) {2259 if (b_mat)
2105 return Array.scalar_mul(b, a);2260 w = b[0].length;
2106 } else if (a_is_array && !b_is_array) {2261 else
2107 return Array.scalar_mul(a, b);2262 w = 1;
2108 }2263 r = [];
2109 h = a.length;2264 if (a_mat && b_mat) {
2110 a_mat = Array.isArray(a[0]);2265 for(i = 0; i < h; i++) {
2111 if (a_mat) {2266 rl = [];
2112 l = a[0].length;2267 for(j = 0; j < w; j++) {
2113 } else {
2114 l = 1;
2115 }
2116 if (l != b.length)
2117 throw RangeError("incompatible matrix size");
2118 b_mat = Array.isArray(b[0]);
2119 if (b_mat)
2120 w = b[0].length;
2121 else
2122 w = 1;
2123 r = [];
2124 if (a_mat && b_mat) {
2125 for(i = 0; i < h; i++) {
2126 rl = [];
2127 for(j = 0; j < w; j++) {
2128 sum = 0;
2129 for(k = 0; k < l; k++) {
2130 sum += a[i][k] * b[k][j];
2131 }
2132 rl[j] = sum;
2133 }
2134 r[i] = rl;
2135 }
2136 } else if (a_mat && !b_mat) {
2137 for(i = 0; i < h; i++) {
2138 sum = 0;2268 sum = 0;
2139 for(k = 0; k < l; k++) {2269 for(k = 0; k < l; k++) {
2140 sum += a[i][k] * b[k];2270 sum += a[i][k] * b[k][j];
2141 }2271 }
2142 r[i] = sum;2272 rl[j] = sum;
2143 }2273 }
2144 } else if (!a_mat && b_mat) {2274 r[i] = rl;
2145 for(i = 0; i < h; i++) {2275 }
2146 rl = [];2276 } else if (a_mat && !b_mat) {
2147 for(j = 0; j < w; j++) {2277 for(i = 0; i < h; i++) {
2148 rl[j] = a[i] * b[0][j];2278 sum = 0;
2149 }2279 for(k = 0; k < l; k++) {
2150 r[i] = rl;2280 sum += a[i][k] * b[k];
2151 }2281 }
2152 } else {2282 r[i] = sum;
2153 for(i = 0; i < h; i++) {2283 }
2154 r[i] = a[i] * b[0];2284 } else if (!a_mat && b_mat) {
2285 for(i = 0; i < h; i++) {
2286 rl = [];
2287 for(j = 0; j < w; j++) {
2288 rl[j] = a[i] * b[0][j];
2155 }2289 }
2290 r[i] = rl;
2156 }2291 }
2157 return r;2292 } else {
2158 },2293 for(i = 0; i < h; i++) {
2159 [Symbol.operatorDiv](a, b) {2294 r[i] = a[i] * b[0];
2160 return Array[Symbol.operatorMul](a, b.inverse());2295 }
2161 },2296 }
2162 [Symbol.operatorPow]: generic_pow,2297 return r;
2163 [Symbol.operatorCmpEQ](a, b) {2298 }
2164 var n, i;2299 function array_div(a, b) {
2165 n = a.length;2300 return array_mul(a, b.inverse());
2166 if (n != b.length)2301 }
2302 function array_scalar_div(a, b) {
2303 return a * b.inverse();
2304 }
2305 function array_eq(a, b) {
2306 var n, i;
2307 n = a.length;
2308 if (n != b.length)
2309 return false;
2310 for(i = 0; i < n; i++) {
2311 if (a[i] != b[i])
2167 return false;2312 return false;
2168 for(i = 0; i < n; i++) {2313 }
2169 if (a[i] != b[i])2314 return true;
2170 return false;2315 }
2316
2317 operators_set(Array.prototype,
2318 {
2319 "+": array_add,
2320 "-": array_sub,
2321 "*": array_mul,
2322 "/": array_div,
2323 "==": array_eq,
2324 "pos"(a) {
2325 return a;
2326 },
2327 "neg"(a) {
2328 var i, n, r;
2329 n = a.length;
2330 r = [];
2331 for(i = 0; i < n; i++)
2332 r[i] = -a[i];
2333 return r;
2171 }2334 }
2172 return true;
2173 },2335 },
2174 });2336 {
2337 right: [Number, BigInt, Float, Fraction, Complex, Mod,
2338 Polynomial, PolyMod, RationalFunction, Series],
2339 "*": array_scalar_mul,
2340 "/": array_scalar_div,
2341 "**": generic_pow, /* XXX: only for integer */
2342 },
2343 {
2344 left: [Number, BigInt, Float, Fraction, Complex, Mod,
2345 Polynomial, PolyMod, RationalFunction, Series],
2346 "*"(a, b) { return array_scalar_mul(b, a); },
2347 "/"(a, b) { return array_scalar_div(b, a); },
2348 });
2175 2349
2176 add_props(Array.prototype, {2350 add_props(Array.prototype, {
2177 [Symbol.operatorPlus]() {
2178 return this;
2179 },
2180 [Symbol.operatorNeg]() {
2181 var i, n, r;
2182 n = this.length;
2183 r = [];
2184 for(i = 0; i < n; i++)
2185 r[i] = -this[i];
2186 return r;
2187 },
2188 conj() {2351 conj() {
2189 var i, n, r;2352 var i, n, r;
2190 n = this.length;2353 n = this.length;
@@ -2426,6 +2589,42 @@ function fromdeg(a) · 235 unmodified lines
2426 return a * Float.PI / 180;2589 return a * Float.PI / 180;
2427}2590}
2428 2591
2592function sinh(a)
2593{
2594 var e = Float.exp(Float(a));
2595 return (e - 1/e) * 0.5;
2596}
2597
2598function cosh(a)
2599{
2600 var e = Float.exp(Float(a));
2601 return (e + 1/e) * 0.5;
2602}
2603
2604function tanh(a)
2605{
2606 var e = Float.exp(Float(a) * 2);
2607 return (e - 1) / (e + 1);
2608}
2609
2610function asinh(a)
2611{
2612 var x = Float(a);
2613 return log(sqrt(x * x + 1) + x);
2614}
2615
2616function acosh(a)
2617{
2618 var x = Float(a);
2619 return log(sqrt(x * x - 1) + x);
2620}
2621
2622function atanh(a)
2623{
2624 var x = Float(a);
2625 return 0.5 * log((1 + x) / (1 - x));
2626}
2627
2429var idn = Matrix.idn;2628var idn = Matrix.idn;
2430var diag = Matrix.diag;2629var diag = Matrix.diag;
2431var trans = Matrix.trans;2630var trans = Matrix.trans;
quickjs-atom.h+4−22
@@ -219,6 +219,8 @@ DEF(BigInt, "BigInt") · 218 unmodified lines
219DEF(BigFloat, "BigFloat")219DEF(BigFloat, "BigFloat")
220DEF(BigFloatEnv, "BigFloatEnv")220DEF(BigFloatEnv, "BigFloatEnv")
221DEF(BigDecimal, "BigDecimal")221DEF(BigDecimal, "BigDecimal")
222DEF(OperatorSet, "OperatorSet")
223DEF(Operators, "Operators")
222#endif224#endif
223DEF(Map, "Map")225DEF(Map, "Map")
224DEF(Set, "Set") /* Map + 1 */226DEF(Set, "Set") /* Map + 1 */
@@ -263,27 +265,7 @@ DEF(Symbol_species, "Symbol.species") · 38 unmodified lines
263DEF(Symbol_unscopables, "Symbol.unscopables")265DEF(Symbol_unscopables, "Symbol.unscopables")
264DEF(Symbol_asyncIterator, "Symbol.asyncIterator")266DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
265#ifdef CONFIG_BIGNUM267#ifdef CONFIG_BIGNUM
266DEF(Symbol_operatorOrder, "Symbol.operatorOrder")268DEF(Symbol_operatorSet, "Symbol.operatorSet")
267DEF(Symbol_operatorAdd, "Symbol.operatorAdd")
268DEF(Symbol_operatorSub, "Symbol.operatorSub")
269DEF(Symbol_operatorMul, "Symbol.operatorMul")
270DEF(Symbol_operatorDiv, "Symbol.operatorDiv")
271DEF(Symbol_operatorMod, "Symbol.operatorMod")
272DEF(Symbol_operatorPow, "Symbol.operatorPow")
273DEF(Symbol_operatorShl, "Symbol.operatorShl")
274DEF(Symbol_operatorShr, "Symbol.operatorShr")
275DEF(Symbol_operatorAnd, "Symbol.operatorAnd")
276DEF(Symbol_operatorOr, "Symbol.operatorOr")
277DEF(Symbol_operatorXor, "Symbol.operatorXor")
278DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT")
279DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE")
280DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ")
281DEF(Symbol_operatorPlus, "Symbol.operatorPlus")
282DEF(Symbol_operatorNeg, "Symbol.operatorNeg")
283DEF(Symbol_operatorNot, "Symbol.operatorNot")
284DEF(Symbol_operatorInc, "Symbol.operatorInc")
285DEF(Symbol_operatorDec, "Symbol.operatorDec")
286DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod")
287#endif269#endif
288 270
289#endif /* DEF */271#endif /* DEF */
quickjs-libc.c+15−0
@@ -2027,6 +2027,20 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, · 2026 unmodified lines
2027 2027
2028#if !defined(_WIN32)2028#if !defined(_WIN32)
2029 2029
2030static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
2031 int argc, JSValueConst *argv)
2032{
2033 const char *target;
2034 int err;
2035
2036 target = JS_ToCString(ctx, argv[0]);
2037 if (!target)
2038 return JS_EXCEPTION;
2039 err = chdir(target);
2040 JS_FreeCString(ctx, target);
2041 return js_os_return(ctx, err);
2042}
2043
2030/* return [path, errorcode] */2044/* return [path, errorcode] */
2031static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,2045static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
2032 int argc, JSValueConst *argv)2046 int argc, JSValueConst *argv)
@@ -2581,6 +2595,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { · 548 unmodified lines
2581 JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),2595 JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
2582 JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),2596 JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
2583#if !defined(_WIN32)2597#if !defined(_WIN32)
2598 JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
2584 JS_CFUNC_DEF("realpath", 1, js_os_realpath ),2599 JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
2585 JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),2600 JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
2586 JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),2601 JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
quickjs-opcode.h+0−3
@@ -260,9 +260,7 @@ DEF( or, 1, 2, 1, none) · 259 unmodified lines
260DEF(is_undefined_or_null, 1, 1, 1, none)260DEF(is_undefined_or_null, 1, 1, 1, none)
261#ifdef CONFIG_BIGNUM261#ifdef CONFIG_BIGNUM
262DEF( mul_pow10, 1, 2, 1, none)262DEF( mul_pow10, 1, 2, 1, none)
263DEF( math_div, 1, 2, 1, none)
264DEF( math_mod, 1, 2, 1, none)263DEF( math_mod, 1, 2, 1, none)
265DEF( math_pow, 1, 2, 1, none)
266#endif264#endif
267/* must be the last non short and non temporary opcode */265/* must be the last non short and non temporary opcode */
268DEF( nop, 1, 0, 0, none) 266DEF( nop, 1, 0, 0, none)
@@ -271,7 +269,6 @@ DEF( nop, 1, 0, 0, none) · 2 unmodified lines
271 269
272def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */270def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
273 271
274def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */
275def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */272def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
276def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */273def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
277 274
quickjs.c+1788−1418
@@ -42,10 +42,6 @@ · 41 unmodified lines
42#include "list.h"42#include "list.h"
43#include "quickjs.h"43#include "quickjs.h"
44#include "libregexp.h"44#include "libregexp.h"
45
46/* enable bignums */
47#define CONFIG_BIGNUM
48
49#ifdef CONFIG_BIGNUM45#ifdef CONFIG_BIGNUM
50#include "libbf.h"46#include "libbf.h"
51#endif47#endif
@@ -151,7 +147,8 @@ enum { · 99 unmodified lines
151 JS_CLASS_BIG_INT, /* u.object_data */147 JS_CLASS_BIG_INT, /* u.object_data */
152 JS_CLASS_BIG_FLOAT, /* u.object_data */148 JS_CLASS_BIG_FLOAT, /* u.object_data */
153 JS_CLASS_FLOAT_ENV, /* u.float_env */149 JS_CLASS_FLOAT_ENV, /* u.float_env */
154 JS_CLASS_BIG_DECIMAL, /* u.object_data */150 JS_CLASS_BIG_DECIMAL, /* u.object_data */
151 JS_CLASS_OPERATOR_SET, /* u.operator_set */
155#endif152#endif
156 JS_CLASS_MAP, /* u.map_state */153 JS_CLASS_MAP, /* u.map_state */
157 JS_CLASS_SET, /* u.map_state */154 JS_CLASS_SET, /* u.map_state */
@@ -285,6 +282,7 @@ struct JSRuntime { · 127 unmodified lines
285 JSNumericOperations bigint_ops;282 JSNumericOperations bigint_ops;
286 JSNumericOperations bigfloat_ops;283 JSNumericOperations bigfloat_ops;
287 JSNumericOperations bigdecimal_ops;284 JSNumericOperations bigdecimal_ops;
285 uint32_t operator_count;
288#endif286#endif
289};287};
290 288
@@ -300,8 +298,7 @@ struct JSClass { · 9 unmodified lines
300 298
301#define JS_MODE_STRICT (1 << 0)299#define JS_MODE_STRICT (1 << 0)
302#define JS_MODE_STRIP (1 << 1)300#define JS_MODE_STRIP (1 << 1)
303#define JS_MODE_BIGINT (1 << 2)301#define JS_MODE_MATH (1 << 2)
304#define JS_MODE_MATH (1 << 3)
305 302
306typedef struct JSStackFrame {303typedef struct JSStackFrame {
307 struct JSStackFrame *prev_frame; /* NULL if first stack frame */304 struct JSStackFrame *prev_frame; /* NULL if first stack frame */
@@ -312,7 +309,7 @@ typedef struct JSStackFrame { · 4 unmodified lines
312 const uint8_t *cur_pc; /* only used in bytecode functions : PC of the309 const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
313 instruction after the call */310 instruction after the call */
314 int arg_count;311 int arg_count;
315 int js_mode; /* 0 or JS_MODE_BIGINT for C functions */312 int js_mode; /* 0 or JS_MODE_MATH for C functions */
316 /* only used in generators. Current stack pointer value. NULL if313 /* only used in generators. Current stack pointer value. NULL if
317 the function is running. */ 314 the function is running. */
318 JSValue *cur_sp;315 JSValue *cur_sp;
@@ -419,8 +416,8 @@ struct JSContext { · 100 unmodified lines
419#ifdef CONFIG_BIGNUM416#ifdef CONFIG_BIGNUM
420 bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */417 bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
421 JSFloatEnv fp_env; /* global FP environment */418 JSFloatEnv fp_env; /* global FP environment */
422 BOOL bignum_ext; /* enable bigint mode, math mode and operator419 BOOL bignum_ext : 8; /* enable math mode */
423 overloading */420 BOOL allow_operator_overloading : 8;
424#endif421#endif
425 /* when the counter reaches zero, JSRutime.interrupt_handler is called */422 /* when the counter reaches zero, JSRutime.interrupt_handler is called */
426 int interrupt_counter;423 int interrupt_counter;
@@ -653,6 +650,53 @@ typedef struct JSAsyncFunctionData { · 226 unmodified lines
653 JSAsyncFunctionState func_state;650 JSAsyncFunctionState func_state;
654} JSAsyncFunctionData;651} JSAsyncFunctionData;
655 652
653typedef enum {
654 /* binary operators */
655 JS_OVOP_ADD,
656 JS_OVOP_SUB,
657 JS_OVOP_MUL,
658 JS_OVOP_DIV,
659 JS_OVOP_MOD,
660 JS_OVOP_POW,
661 JS_OVOP_OR,
662 JS_OVOP_AND,
663 JS_OVOP_XOR,
664 JS_OVOP_SHL,
665 JS_OVOP_SAR,
666 JS_OVOP_SHR,
667 JS_OVOP_EQ,
668 JS_OVOP_LESS,
669
670 JS_OVOP_BINARY_COUNT,
671 /* unary operators */
672 JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
673 JS_OVOP_NEG,
674 JS_OVOP_INC,
675 JS_OVOP_DEC,
676 JS_OVOP_NOT,
677
678 JS_OVOP_COUNT,
679} JSOverloadableOperatorEnum;
680
681typedef struct {
682 uint32_t operator_index;
683 JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
684} JSBinaryOperatorDefEntry;
685
686typedef struct {
687 int count;
688 JSBinaryOperatorDefEntry *tab;
689} JSBinaryOperatorDef;
690
691typedef struct {
692 uint32_t operator_counter;
693 BOOL is_primitive; /* OperatorSet for a primitive type */
694 /* NULL if no operator is defined */
695 JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
696 JSBinaryOperatorDef left;
697 JSBinaryOperatorDef right;
698} JSOperatorSetData;
699
656typedef struct JSReqModuleEntry {700typedef struct JSReqModuleEntry {
657 JSAtom module_name;701 JSAtom module_name;
658 JSModuleDef *module; /* used using resolution */702 JSModuleDef *module; /* used using resolution */
@@ -808,6 +852,7 @@ struct JSObject { · 149 unmodified lines
808 struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */852 struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
809#ifdef CONFIG_BIGNUM853#ifdef CONFIG_BIGNUM
810 struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */854 struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
855 struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
811#endif856#endif
812 struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */857 struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
813 struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */858 struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
@@ -991,6 +1036,11 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val, · 177 unmodified lines
991static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);1036static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
992static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,1037static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
993 JS_MarkFunc *mark_func);1038 JS_MarkFunc *mark_func);
1039#ifdef CONFIG_BIGNUM
1040static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
1041static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
1042 JS_MarkFunc *mark_func);
1043#endif
994static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);1044static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
995static int JS_ToBoolFree(JSContext *ctx, JSValue val);1045static int JS_ToBoolFree(JSContext *ctx, JSValue val);
996static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);1046static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
@@ -1021,10 +1071,27 @@ static JSProperty *add_property(JSContext *ctx, · 24 unmodified lines
1021 JSObject *p, JSAtom prop, int prop_flags);1071 JSObject *p, JSAtom prop, int prop_flags);
1022#ifdef CONFIG_BIGNUM1072#ifdef CONFIG_BIGNUM
1023static void js_float_env_finalizer(JSRuntime *rt, JSValue val);1073static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
1024static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a);1074static JSValue JS_NewBigFloat(JSContext *ctx);
1025static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a);1075static inline bf_t *JS_GetBigFloat(JSValueConst val)
1026static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint);1076{
1027static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a);1077 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1078 return &p->num;
1079}
1080static JSValue JS_NewBigDecimal(JSContext *ctx);
1081static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
1082{
1083 JSBigDecimal *p = JS_VALUE_GET_PTR(val);
1084 return &p->num;
1085}
1086static JSValue JS_NewBigInt(JSContext *ctx);
1087static inline bf_t *JS_GetBigInt(JSValueConst val)
1088{
1089 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1090 return &p->num;
1091}
1092static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
1093 BOOL convert_to_safe_integer);
1094static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
1028static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);1095static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
1029static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);1096static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
1030static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);1097static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
@@ -1123,19 +1190,6 @@ static const JSClassExoticMethods js_proxy_exotic_methods; · 92 unmodified lines
1123static const JSClassExoticMethods js_module_ns_exotic_methods;1190static const JSClassExoticMethods js_module_ns_exotic_methods;
1124static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;1191static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
1125 1192
1126JS_BOOL JS_IsNumber(JSValueConst v)
1127{
1128#ifdef CONFIG_BIGNUM
1129 /* XXX: check the bignum case. Should use a different function */
1130 int tag = JS_VALUE_GET_TAG(v);
1131 return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
1132 tag == JS_TAG_BIG_FLOAT || JS_TAG_IS_FLOAT64(tag);
1133#else
1134 int tag = JS_VALUE_GET_TAG(v);
1135 return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
1136#endif
1137}
1138
1139static void js_trigger_gc(JSRuntime *rt, size_t size)1193static void js_trigger_gc(JSRuntime *rt, size_t size)
1140{1194{
1141 BOOL force_gc;1195 BOOL force_gc;
@@ -1333,6 +1387,7 @@ static JSClassShortDef const js_std_class_def[] = { · 191 unmodified lines
1333 { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */1387 { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */
1334 { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */1388 { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */
1335 { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */1389 { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */
1390 { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */
1336#endif1391#endif
1337 { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */1392 { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */
1338 { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */1393 { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */
@@ -2136,10 +2191,10 @@ static inline BOOL is_strict_mode(JSContext *ctx) · 797 unmodified lines
2136}2191}
2137 2192
2138#ifdef CONFIG_BIGNUM2193#ifdef CONFIG_BIGNUM
2139static inline BOOL is_bigint_mode(JSContext *ctx)2194static inline BOOL is_math_mode(JSContext *ctx)
2140{2195{
2141 JSStackFrame *sf = ctx->current_stack_frame;2196 JSStackFrame *sf = ctx->current_stack_frame;
2142 return (sf && (sf->js_mode & JS_MODE_BIGINT));2197 return (sf && (sf->js_mode & JS_MODE_MATH));
2143}2198}
2144#endif2199#endif
2145 2200
@@ -2148,25 +2203,12 @@ JSValue JS_NewInt64(JSContext *ctx, int64_t v) · 2 unmodified lines
2148 if (v == (int32_t)v) {2203 if (v == (int32_t)v) {
2149 return JS_NewInt32(ctx, v);2204 return JS_NewInt32(ctx, v);
2150 } else {2205 } else {
2151#ifdef CONFIG_BIGNUM2206 return __JS_NewFloat64(ctx, (double)v);
2152 if (is_bigint_mode(ctx)) {
2153 bf_t a_s, *a = &a_s;
2154 bf_init(ctx->bf_ctx, a);
2155 bf_set_si(a, v);
2156 return JS_NewBigInt(ctx, a);
2157 } else
2158#endif
2159 {
2160 return __JS_NewFloat64(ctx, (double)v);
2161 }
2162 }2207 }
2163}2208}
2164 2209
2165static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)2210static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
2166{2211{
2167#ifdef CONFIG_BIGNUM
2168 return JS_NewInt64(ctx, val);
2169#else
2170 JSValue v;2212 JSValue v;
2171 if (val <= 0x7fffffff) {2213 if (val <= 0x7fffffff) {
2172 v = JS_MKVAL(JS_TAG_INT, val);2214 v = JS_MKVAL(JS_TAG_INT, val);
@@ -2174,7 +2216,6 @@ static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) · 1 unmodified line
2174 v = __JS_NewFloat64(ctx, val);2216 v = __JS_NewFloat64(ctx, val);
2175 }2217 }
2176 return v;2218 return v;
2177#endif
2178}2219}
2179 2220
2180/* JSAtom support */2221/* JSAtom support */
@@ -5720,6 +5761,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) · 3539 unmodified lines
5720#ifdef CONFIG_BIGNUM5761#ifdef CONFIG_BIGNUM
5721 case JS_CLASS_BIG_INT: /* u.object_data */5762 case JS_CLASS_BIG_INT: /* u.object_data */
5722 case JS_CLASS_BIG_FLOAT: /* u.object_data */5763 case JS_CLASS_BIG_FLOAT: /* u.object_data */
5764 case JS_CLASS_BIG_DECIMAL: /* u.object_data */
5723#endif5765#endif
5724 compute_value_size(p->u.object_data, hp);5766 compute_value_size(p->u.object_data, hp);
5725 break;5767 break;
@@ -6515,28 +6557,17 @@ JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val) · 789 unmodified lines
6515 case JS_TAG_BIG_INT:6557 case JS_TAG_BIG_INT:
6516 val = ctx->class_proto[JS_CLASS_BIG_INT];6558 val = ctx->class_proto[JS_CLASS_BIG_INT];
6517 break;6559 break;
6518 case JS_TAG_INT:
6519 if (is_bigint_mode(ctx)) {
6520 val = ctx->class_proto[JS_CLASS_BIG_INT];
6521 } else {
6522 val = ctx->class_proto[JS_CLASS_NUMBER];
6523 }
6524 break;
6525 case JS_TAG_FLOAT64:
6526 val = ctx->class_proto[JS_CLASS_NUMBER];
6527 break;
6528 case JS_TAG_BIG_FLOAT:6560 case JS_TAG_BIG_FLOAT:
6529 val = ctx->class_proto[JS_CLASS_BIG_FLOAT];6561 val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
6530 break;6562 break;
6531 case JS_TAG_BIG_DECIMAL:6563 case JS_TAG_BIG_DECIMAL:
6532 val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];6564 val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
6533 break;6565 break;
6534#else6566#endif
6535 case JS_TAG_INT:6567 case JS_TAG_INT:
6536 case JS_TAG_FLOAT64:6568 case JS_TAG_FLOAT64:
6537 val = ctx->class_proto[JS_CLASS_NUMBER];6569 val = ctx->class_proto[JS_CLASS_NUMBER];
6538 break;6570 break;
6539#endif
6540 case JS_TAG_BOOL:6571 case JS_TAG_BOOL:
6541 val = ctx->class_proto[JS_CLASS_BOOLEAN];6572 val = ctx->class_proto[JS_CLASS_BOOLEAN];
6542 break;6573 break;
@@ -7750,11 +7781,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSProperty *prop, · 1207 unmodified lines
7750 }7781 }
7751 p->u.array.count = len;7782 p->u.array.count = len;
7752 }7783 }
7753#ifdef CONFIG_BIGNUM
7754 set_value(ctx, &prop->u.value, JS_NewUint32(ctx, len));
7755#else
7756 prop->u.value = JS_NewUint32(ctx, len);7784 prop->u.value = JS_NewUint32(ctx, len);
7757#endif
7758 } else {7785 } else {
7759 /* Note: length is always a uint32 because the object is an7786 /* Note: length is always a uint32 because the object is an
7760 array */7787 array */
@@ -9352,9 +9379,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) · 1591 unmodified lines
9352#define HINT_STRING 09379#define HINT_STRING 0
9353#define HINT_NUMBER 19380#define HINT_NUMBER 1
9354#define HINT_NONE 29381#define HINT_NONE 2
9355#ifdef CONFIG_BIGNUM
9356#define HINT_INTEGER 3
9357#endif
9358/* don't try Symbol.toPrimitive */9382/* don't try Symbol.toPrimitive */
9359#define HINT_FORCE_ORDINARY (1 << 4)9383#define HINT_FORCE_ORDINARY (1 << 4)
9360 9384
@@ -9389,11 +9413,6 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) · 28 unmodified lines
9389 case HINT_NONE:9413 case HINT_NONE:
9390 atom = JS_ATOM_default;9414 atom = JS_ATOM_default;
9391 break;9415 break;
9392#ifdef CONFIG_BIGNUM
9393 case HINT_INTEGER:
9394 atom = JS_ATOM_integer;
9395 break;
9396#endif
9397 }9416 }
9398 arg = JS_AtomToString(ctx, atom);9417 arg = JS_AtomToString(ctx, atom);
9399 ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);9418 ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
@@ -9605,22 +9624,31 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, · 205 unmodified lines
9605{9624{
9606 bf_t a_s, *a = &a_s;9625 bf_t a_s, *a = &a_s;
9607 int ret;9626 int ret;
9608 bf_init(ctx->bf_ctx, a);9627 JSValue val;
9628 val = JS_NewBigInt(ctx);
9629 if (JS_IsException(val))
9630 return val;
9631 a = JS_GetBigInt(val);
9609 ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);9632 ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
9610 if (ret & BF_ST_MEM_ERROR) {9633 if (ret & BF_ST_MEM_ERROR) {
9611 bf_delete(a);9634 JS_FreeValue(ctx, val);
9612 return JS_ThrowOutOfMemory(ctx);9635 return JS_ThrowOutOfMemory(ctx);
9613 }9636 }
9614 return JS_NewBigInt2(ctx, a, !(flags & ATOD_MODE_BIGINT));9637 val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
9638 return val;
9615}9639}
9616 9640
9617static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,9641static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
9618 int radix, int flags, slimb_t *pexponent)9642 int radix, int flags, slimb_t *pexponent)
9619{9643{
9620 bf_t a_s, *a = &a_s;9644 bf_t *a;
9621 int ret;9645 int ret;
9622 9646 JSValue val;
9623 bf_init(ctx->bf_ctx, a);9647
9648 val = JS_NewBigFloat(ctx);
9649 if (JS_IsException(val))
9650 return val;
9651 a = JS_GetBigFloat(val);
9624 if (flags & ATOD_ACCEPT_SUFFIX) {9652 if (flags & ATOD_ACCEPT_SUFFIX) {
9625 /* return the exponent to get infinite precision */9653 /* return the exponent to get infinite precision */
9626 ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,9654 ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
@@ -9630,25 +9658,30 @@ static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, · 3 unmodified lines
9630 ctx->fp_env.flags);9658 ctx->fp_env.flags);
9631 }9659 }
9632 if (ret & BF_ST_MEM_ERROR) {9660 if (ret & BF_ST_MEM_ERROR) {
9633 bf_delete(a);9661 JS_FreeValue(ctx, val);
9634 return JS_ThrowOutOfMemory(ctx);9662 return JS_ThrowOutOfMemory(ctx);
9635 }9663 }
9636 return JS_NewBigFloat(ctx, a);9664 return val;
9637}9665}
9638 9666
9639static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,9667static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
9640 int radix, int flags, slimb_t *pexponent)9668 int radix, int flags, slimb_t *pexponent)
9641{9669{
9642 bfdec_t a_s, *a = &a_s;9670 bfdec_t *a;
9643 int ret;9671 int ret;
9644 bfdec_init(ctx->bf_ctx, a);9672 JSValue val;
9673
9674 val = JS_NewBigDecimal(ctx);
9675 if (JS_IsException(val))
9676 return val;
9677 a = JS_GetBigDecimal(val);
9645 ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,9678 ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
9646 BF_RNDZ | BF_ATOF_NO_NAN_INF);9679 BF_RNDZ | BF_ATOF_NO_NAN_INF);
9647 if (ret & BF_ST_MEM_ERROR) {9680 if (ret & BF_ST_MEM_ERROR) {
9648 bfdec_delete(a);9681 JS_FreeValue(ctx, val);
9649 return JS_ThrowOutOfMemory(ctx);9682 return JS_ThrowOutOfMemory(ctx);
9650 }9683 }
9651 return JS_NewBigDecimal(ctx, a);9684 return val;
9652}9685}
9653 9686
9654#endif9687#endif
@@ -9730,10 +9763,12 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 75 unmodified lines
9730 strstart(p, "Infinity", &p)) {9763 strstart(p, "Infinity", &p)) {
9731#ifdef CONFIG_BIGNUM9764#ifdef CONFIG_BIGNUM
9732 if (atod_type == ATOD_TYPE_BIG_FLOAT) {9765 if (atod_type == ATOD_TYPE_BIG_FLOAT) {
9733 bf_t a_s, *a = &a_s;9766 bf_t *a;
9734 bf_init(ctx->bf_ctx, a);9767 val = JS_NewBigFloat(ctx);
9768 if (JS_IsException(val))
9769 goto done;
9770 a = JS_GetBigFloat(val);
9735 bf_set_inf(a, is_neg);9771 bf_set_inf(a, is_neg);
9736 val = JS_NewBigFloat(ctx, a);
9737 } else9772 } else
9738#endif9773#endif
9739 {9774 {
@@ -9810,7 +9845,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 70 unmodified lines
9810 } else if (*p == 'l') {9845 } else if (*p == 'l') {
9811 p++;9846 p++;
9812 atod_type = ATOD_TYPE_BIG_FLOAT;9847 atod_type = ATOD_TYPE_BIG_FLOAT;
9813 } else if (*p == 'd') {9848 } else if (*p == 'm') {
9814 p++;9849 p++;
9815 atod_type = ATOD_TYPE_BIG_DECIMAL;9850 atod_type = ATOD_TYPE_BIG_DECIMAL;
9816 } else {9851 } else {
@@ -9901,7 +9936,6 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 84 unmodified lines
9901 9936
9902typedef enum JSToNumberHintEnum {9937typedef enum JSToNumberHintEnum {
9903 TON_FLAG_NUMBER,9938 TON_FLAG_NUMBER,
9904 TON_FLAG_INTEGER,
9905 TON_FLAG_NUMERIC,9939 TON_FLAG_NUMERIC,
9906} JSToNumberHintEnum;9940} JSToNumberHintEnum;
9907 9941
@@ -9910,7 +9944,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 2 unmodified lines
9910{9944{
9911 uint32_t tag;9945 uint32_t tag;
9912 JSValue ret;9946 JSValue ret;
9913 int hint;
9914 9947
9915 redo:9948 redo:
9916 tag = JS_VALUE_GET_NORM_TAG(val);9949 tag = JS_VALUE_GET_NORM_TAG(val);
@@ -9924,12 +9957,19 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 7 unmodified lines
9924 ret = val;9957 ret = val;
9925 break;9958 break;
9926 case JS_TAG_BIG_INT:9959 case JS_TAG_BIG_INT:
9927 if (flag == TON_FLAG_NUMBER && !is_bigint_mode(ctx)) {9960 if (flag != TON_FLAG_NUMERIC) {
9928 JS_FreeValue(ctx, val);9961 JS_FreeValue(ctx, val);
9929 return JS_ThrowTypeError(ctx, "cannot convert bigint to number");9962 return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
9930 }9963 }
9931 /* fall thru */9964 ret = val;
9965 break;
9932 case JS_TAG_BIG_FLOAT:9966 case JS_TAG_BIG_FLOAT:
9967 if (flag != TON_FLAG_NUMERIC) {
9968 JS_FreeValue(ctx, val);
9969 return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
9970 }
9971 ret = val;
9972 break;
9933#endif9973#endif
9934 case JS_TAG_FLOAT64:9974 case JS_TAG_FLOAT64:
9935 case JS_TAG_INT:9975 case JS_TAG_INT:
@@ -9944,12 +9984,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 8 unmodified lines
9944 ret = JS_NAN;9984 ret = JS_NAN;
9945 break;9985 break;
9946 case JS_TAG_OBJECT:9986 case JS_TAG_OBJECT:
9947#ifdef CONFIG_BIGNUM9987 val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
9948 hint = flag == TON_FLAG_INTEGER ? HINT_INTEGER : HINT_NUMBER;
9949#else
9950 hint = HINT_NUMBER;
9951#endif
9952 val = JS_ToPrimitiveFree(ctx, val, hint);
9953 if (JS_IsException(val))9988 if (JS_IsException(val))
9954 return JS_EXCEPTION;9989 return JS_EXCEPTION;
9955 goto redo;9990 goto redo;
@@ -9969,10 +10004,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 13 unmodified lines
9969 ret = JS_NewInt32(ctx, 0);10004 ret = JS_NewInt32(ctx, 0);
9970 } else {10005 } else {
9971 int flags = ATOD_ACCEPT_BIN_OCT;10006 int flags = ATOD_ACCEPT_BIN_OCT;
9972#ifdef CONFIG_BIGNUM
9973 if (is_bigint_mode(ctx))
9974 flags |= ATOD_MODE_BIGINT;
9975#endif
9976 ret = js_atof(ctx, p, &p, 0, flags);10007 ret = js_atof(ctx, p, &p, 0, flags);
9977 if (!JS_IsException(ret)) {10008 if (!JS_IsException(ret)) {
9978 p += skip_spaces(p);10009 p += skip_spaces(p);
@@ -10001,7 +10032,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) · 22 unmodified lines
10001 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);10032 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
10002}10033}
10003 10034
10004#ifdef CONFIG_BIGNUM
10005static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)10035static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
10006{10036{
10007 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);10037 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
@@ -10011,7 +10041,6 @@ static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) · 3 unmodified lines
10011{10041{
10012 return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));10042 return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
10013}10043}
10014#endif
10015 10044
10016static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,10045static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
10017 JSValue val)10046 JSValue val)
@@ -10078,6 +10107,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) · 60 unmodified lines
10078 return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));10107 return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
10079}10108}
10080 10109
10110/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
10081static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)10111static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
10082{10112{
10083 uint32_t tag;10113 uint32_t tag;
@@ -10106,11 +10136,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 22 unmodified lines
10106 }10136 }
10107 break;10137 break;
10108#ifdef CONFIG_BIGNUM10138#ifdef CONFIG_BIGNUM
10109 case JS_TAG_BIG_INT:
10110 if (!is_bigint_mode(ctx))
10111 goto to_number;
10112 ret = val;
10113 break;
10114 case JS_TAG_BIG_FLOAT:10139 case JS_TAG_BIG_FLOAT:
10115 {10140 {
10116 bf_t a_s, *a, r_s, *r = &r_s;10141 bf_t a_s, *a, r_s, *r = &r_s;
@@ -10124,10 +10149,13 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 7 unmodified lines
10124 else10149 else
10125 ret = JS_DupValue(ctx, val);10150 ret = JS_DupValue(ctx, val);
10126 } else {10151 } else {
10127 bf_init(ctx->bf_ctx, r);10152 ret = JS_NewBigInt(ctx);
10128 bf_set(r, a);10153 if (!JS_IsException(ret)) {
10129 bf_rint(r, BF_RNDZ);10154 r = JS_GetBigInt(ret);
10130 ret = JS_NewBigInt(ctx, r);10155 bf_set(r, a);
10156 bf_rint(r, BF_RNDZ);
10157 ret = JS_CompactBigInt(ctx, ret);
10158 }
10131 }10159 }
10132 if (a == &a_s)10160 if (a == &a_s)
10133 bf_delete(a);10161 bf_delete(a);
@@ -10136,9 +10164,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 2 unmodified lines
10136 break;10164 break;
10137#endif10165#endif
10138 default:10166 default:
10139#ifdef CONFIG_BIGNUM
10140 to_number:
10141#endif
10142 val = JS_ToNumberFree(ctx, val);10167 val = JS_ToNumberFree(ctx, val);
10143 if (JS_IsException(val))10168 if (JS_IsException(val))
10144 return val;10169 return val;
@@ -10182,17 +10207,12 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) · 37 unmodified lines
10182 break;10207 break;
10183#ifdef CONFIG_BIGNUM10208#ifdef CONFIG_BIGNUM
10184 case JS_TAG_BIG_FLOAT:10209 case JS_TAG_BIG_FLOAT:
10185 to_bf:
10186 {10210 {
10187 JSBigFloat *p = JS_VALUE_GET_PTR(val);10211 JSBigFloat *p = JS_VALUE_GET_PTR(val);
10188 bf_get_int32(&ret, &p->num, 0);10212 bf_get_int32(&ret, &p->num, 0);
10189 JS_FreeValue(ctx, val);10213 JS_FreeValue(ctx, val);
10190 }10214 }
10191 break;10215 break;
10192 case JS_TAG_BIG_INT:
10193 if (is_bigint_mode(ctx))
10194 goto to_bf;
10195 /* fall thru */
10196#endif10216#endif
10197 default:10217 default:
10198 val = JS_ToNumberFree(ctx, val);10218 val = JS_ToNumberFree(ctx, val);
@@ -10261,17 +10281,12 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) · 62 unmodified lines
10261 return 0;10281 return 0;
10262#ifdef CONFIG_BIGNUM10282#ifdef CONFIG_BIGNUM
10263 case JS_TAG_BIG_FLOAT:10283 case JS_TAG_BIG_FLOAT:
10264 to_bf:
10265 {10284 {
10266 JSBigFloat *p = JS_VALUE_GET_PTR(val);10285 JSBigFloat *p = JS_VALUE_GET_PTR(val);
10267 bf_get_int64(pres, &p->num, 0);10286 bf_get_int64(pres, &p->num, 0);
10268 JS_FreeValue(ctx, val);10287 JS_FreeValue(ctx, val);
10269 }10288 }
10270 return 0;10289 return 0;
10271 case JS_TAG_BIG_INT:
10272 if (is_bigint_mode(ctx))
10273 goto to_bf;
10274 /* fall thru */
10275#endif10290#endif
10276 default:10291 default:
10277 val = JS_ToNumberFree(ctx, val);10292 val = JS_ToNumberFree(ctx, val);
@@ -10346,17 +10361,12 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) · 68 unmodified lines
10346 break;10361 break;
10347#ifdef CONFIG_BIGNUM10362#ifdef CONFIG_BIGNUM
10348 case JS_TAG_BIG_FLOAT:10363 case JS_TAG_BIG_FLOAT:
10349 to_bf:
10350 {10364 {
10351 JSBigFloat *p = JS_VALUE_GET_PTR(val);10365 JSBigFloat *p = JS_VALUE_GET_PTR(val);
10352 bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);10366 bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
10353 JS_FreeValue(ctx, val);10367 JS_FreeValue(ctx, val);
10354 }10368 }
10355 break;10369 break;
10356 case JS_TAG_BIG_INT:
10357 if (is_bigint_mode(ctx))
10358 goto to_bf;
10359 /* fall thru */
10360#endif10370#endif
10361 default:10371 default:
10362 val = JS_ToNumberFree(ctx, val);10372 val = JS_ToNumberFree(ctx, val);
@@ -10418,17 +10428,12 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) · 55 unmodified lines
10418 break;10428 break;
10419#ifdef CONFIG_BIGNUM10429#ifdef CONFIG_BIGNUM
10420 case JS_TAG_BIG_FLOAT:10430 case JS_TAG_BIG_FLOAT:
10421 to_bf:
10422 {10431 {
10423 JSBigFloat *p = JS_VALUE_GET_PTR(val);10432 JSBigFloat *p = JS_VALUE_GET_PTR(val);
10424 bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);10433 bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
10425 JS_FreeValue(ctx, val);10434 JS_FreeValue(ctx, val);
10426 }10435 }
10427 break;10436 break;
10428 case JS_TAG_BIG_INT:
10429 if (is_bigint_mode(ctx))
10430 goto to_bf;
10431 /* fall thru */
10432#endif10437#endif
10433 default:10438 default:
10434 val = JS_ToNumberFree(ctx, val);10439 val = JS_ToNumberFree(ctx, val);
@@ -10486,15 +10491,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) · 51 unmodified lines
10486 }10491 }
10487 break;10492 break;
10488#ifdef CONFIG_BIGNUM10493#ifdef CONFIG_BIGNUM
10489 case JS_TAG_BIG_INT:
10490 {
10491 JSBigFloat *p = JS_VALUE_GET_PTR(val);
10492 if (!is_bigint_mode(ctx))
10493 goto to_number;
10494 bf_get_int32(&res, &p->num, 0);
10495 JS_FreeValue(ctx, val);
10496 }
10497 goto int_clamp;
10498 case JS_TAG_BIG_FLOAT:10494 case JS_TAG_BIG_FLOAT:
10499 {10495 {
10500 JSBigFloat *p = JS_VALUE_GET_PTR(val);10496 JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -10509,9 +10505,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) · 8 unmodified lines
10509 goto int_clamp;10505 goto int_clamp;
10510#endif10506#endif
10511 default:10507 default:
10512#ifdef CONFIG_BIGNUM
10513 to_number:
10514#endif
10515 val = JS_ToNumberFree(ctx, val);10508 val = JS_ToNumberFree(ctx, val);
10516 if (JS_IsException(val)) {10509 if (JS_IsException(val)) {
10517 *pres = 0;10510 *pres = 0;
@@ -10584,6 +10577,12 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, · 66 unmodified lines
10584 10577
10585#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)10578#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
10586 10579
10580static BOOL is_safe_integer(double d)
10581{
10582 return isfinite(d) && floor(d) == d &&
10583 fabs(d) <= (double)MAX_SAFE_INTEGER;
10584}
10585
10587int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)10586int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
10588{10587{
10589 int64_t v;10588 int64_t v;
@@ -10609,7 +10608,6 @@ static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, · 19 unmodified lines
10609}10608}
10610 10609
10611/* Note: can return an exception */10610/* Note: can return an exception */
10612/* XXX: bignum case */
10613static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)10611static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
10614{10612{
10615 double d;10613 double d;
@@ -10753,7 +10751,8 @@ static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val) · 137 unmodified lines
10753 return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);10751 return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
10754}10752}
10755 10753
10756static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)10754static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
10755 limb_t prec, int flags)
10757{10756{
10758 JSValue ret;10757 JSValue ret;
10759 bfdec_t *a;10758 bfdec_t *a;
@@ -10764,8 +10763,7 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) · 4 unmodified lines
10764 saved_sign = a->sign;10763 saved_sign = a->sign;
10765 if (a->expn == BF_EXP_ZERO)10764 if (a->expn == BF_EXP_ZERO)
10766 a->sign = 0;10765 a->sign = 0;
10767 str = bfdec_ftoa(NULL, a, 0, BF_RNDZ | BF_FTOA_FORMAT_FREE |10766 str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
10768 BF_FTOA_JS_QUIRKS);
10769 a->sign = saved_sign;10767 a->sign = saved_sign;
10770 if (!str)10768 if (!str)
10771 return JS_ThrowOutOfMemory(ctx);10769 return JS_ThrowOutOfMemory(ctx);
@@ -10774,6 +10772,12 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) · 2 unmodified lines
10774 return ret;10772 return ret;
10775}10773}
10776 10774
10775static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
10776{
10777 return js_bigdecimal_to_string1(ctx, val, 0,
10778 BF_RNDZ | BF_FTOA_FORMAT_FREE);
10779}
10780
10777#endif /* CONFIG_BIGNUM */10781#endif /* CONFIG_BIGNUM */
10778 10782
10779/* 2 <= base <= 36 */10783/* 2 <= base <= 36 */
@@ -11478,30 +11482,48 @@ static double js_pow(double a, double b) · 698 unmodified lines
11478 11482
11479#ifdef CONFIG_BIGNUM11483#ifdef CONFIG_BIGNUM
11480 11484
11485JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
11486{
11487 JSValue val;
11488 bf_t *a;
11489 val = JS_NewBigInt(ctx);
11490 if (JS_IsException(val))
11491 return val;
11492 a = JS_GetBigInt(val);
11493 if (bf_set_si(a, v)) {
11494 JS_FreeValue(ctx, val);
11495 return JS_ThrowOutOfMemory(ctx);
11496 }
11497 return val;
11498}
11499
11481JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)11500JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
11482{11501{
11483 BOOL is_bignum = is_bigint_mode(ctx);11502 if (is_math_mode(ctx) &&
11484 if (is_bignum && v == (int32_t)v) {11503 v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
11485 return JS_NewInt32(ctx, v);11504 return JS_NewInt64(ctx, v);
11486 } else {11505 } else {
11487 bf_t a_s, *a = &a_s;11506 return JS_NewBigInt64_1(ctx, v);
11488 bf_init(ctx->bf_ctx, a);
11489 bf_set_si(a, v);
11490 return JS_NewBigInt2(ctx, a, TRUE);
11491 }11507 }
11492}11508}
11493 11509
11494JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)11510JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
11495{11511{
11496 BOOL is_bignum = is_bigint_mode(ctx);11512 JSValue val;
11497 if (is_bignum && v == (int32_t)v) {11513 if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
11498 return JS_NewInt32(ctx, v);11514 val = JS_NewInt64(ctx, v);
11499 } else {11515 } else {
11500 bf_t a_s, *a = &a_s;11516 bf_t *a;
11501 bf_init(ctx->bf_ctx, a);11517 val = JS_NewBigInt(ctx);
11502 bf_set_ui(a, v);11518 if (JS_IsException(val))
11503 return JS_NewBigInt2(ctx, a, TRUE);11519 return val;
11520 a = JS_GetBigInt(val);
11521 if (bf_set_ui(a, v)) {
11522 JS_FreeValue(ctx, val);
11523 return JS_ThrowOutOfMemory(ctx);
11524 }
11504 }11525 }
11526 return val;
11505}11527}
11506 11528
11507/* if the returned bigfloat is allocated it is equal to11529/* if the returned bigfloat is allocated it is equal to
@@ -11582,13 +11604,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) · 74 unmodified lines
11582 p = str;11604 p = str;
11583 p += skip_spaces(p);11605 p += skip_spaces(p);
11584 if ((p - str) == len) {11606 if ((p - str) == len) {
11585 bf_t a_s, *a = &a_s;11607 val = JS_NewBigInt64(ctx, 0);
11586 bf_init(ctx->bf_ctx, a);
11587 bf_set_si(a, 0);
11588 val = JS_NewBigInt(ctx, a);
11589 } else {11608 } else {
11590 flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;11609 flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
11591 if (is_bigint_mode(ctx))11610 if (is_math_mode(ctx))
11592 flags |= ATOD_MODE_BIGINT;11611 flags |= ATOD_MODE_BIGINT;
11593 val = js_atof(ctx, p, &p, 0, flags);11612 val = js_atof(ctx, p, &p, 0, flags);
11594 p += skip_spaces(p);11613 p += skip_spaces(p);
@@ -11625,7 +11644,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 30 unmodified lines
11625 case JS_TAG_INT:11644 case JS_TAG_INT:
11626 case JS_TAG_NULL:11645 case JS_TAG_NULL:
11627 case JS_TAG_UNDEFINED:11646 case JS_TAG_UNDEFINED:
11628 if (!is_bigint_mode(ctx))11647 if (!is_math_mode(ctx))
11629 goto fail;11648 goto fail;
11630 /* fall tru */11649 /* fall tru */
11631 case JS_TAG_BOOL:11650 case JS_TAG_BOOL:
@@ -11636,7 +11655,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 4 unmodified lines
11636 case JS_TAG_FLOAT64:11655 case JS_TAG_FLOAT64:
11637 {11656 {
11638 double d = JS_VALUE_GET_FLOAT64(val);11657 double d = JS_VALUE_GET_FLOAT64(val);
11639 if (!is_bigint_mode(ctx))11658 if (!is_math_mode(ctx))
11640 goto fail;11659 goto fail;
11641 if (!isfinite(d))11660 if (!isfinite(d))
11642 goto fail;11661 goto fail;
@@ -11651,7 +11670,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 8 unmodified lines
11651 r = &p->num;11670 r = &p->num;
11652 break;11671 break;
11653 case JS_TAG_BIG_FLOAT:11672 case JS_TAG_BIG_FLOAT:
11654 if (!is_bigint_mode(ctx))11673 if (!is_math_mode(ctx))
11655 goto fail;11674 goto fail;
11656 p = JS_VALUE_GET_PTR(val);11675 p = JS_VALUE_GET_PTR(val);
11657 if (!bf_is_finite(&p->num))11676 if (!bf_is_finite(&p->num))
@@ -11668,8 +11687,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 10 unmodified lines
11668 return NULL;11687 return NULL;
11669 goto redo;11688 goto redo;
11670 case JS_TAG_OBJECT:11689 case JS_TAG_OBJECT:
11671 val = JS_ToPrimitiveFree(ctx, val,11690 val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
11672 is_bigint_mode(ctx) ? HINT_INTEGER : HINT_NUMBER);
11673 if (JS_IsException(val))11691 if (JS_IsException(val))
11674 return NULL;11692 return NULL;
11675 goto redo;11693 goto redo;
@@ -11692,21 +11710,26 @@ static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) · 16 unmodified lines
11692 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {11710 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
11693 return val;11711 return val;
11694 } else {11712 } else {
11695 bf_t a_s, *a, b_s, *b;11713 bf_t a_s, *a, *r;
11696 int ret;11714 int ret;
11697 11715 JSValue res;
11716
11717 res = JS_NewBigInt(ctx);
11718 if (JS_IsException(res))
11719 return JS_EXCEPTION;
11698 a = JS_ToBigIntFree(ctx, &a_s, val);11720 a = JS_ToBigIntFree(ctx, &a_s, val);
11699 if (!a)11721 if (!a) {
11722 JS_FreeValue(ctx, res);
11700 return JS_EXCEPTION;11723 return JS_EXCEPTION;
11701 b = &b_s;11724 }
11702 bf_init(ctx->bf_ctx, b);11725 r = JS_GetBigInt(res);
11703 ret = bf_set(b, a);11726 ret = bf_set(r, a);
11704 JS_FreeBigInt(ctx, a, &a_s);11727 JS_FreeBigInt(ctx, a, &a_s);
11705 if (ret) {11728 if (ret) {
11706 bf_delete(b);11729 JS_FreeValue(ctx, res);
11707 return JS_ThrowOutOfMemory(ctx);11730 return JS_ThrowOutOfMemory(ctx);
11708 }11731 }
11709 return JS_NewBigInt2(ctx, b, TRUE);11732 return JS_CompactBigInt(ctx, res);
11710 }11733 }
11711}11734}
11712 11735
@@ -11745,7 +11768,7 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) · 32 unmodified lines
11745static JSBigFloat *js_new_bf(JSContext *ctx)11768static JSBigFloat *js_new_bf(JSContext *ctx)
11746{11769{
11747 JSBigFloat *p;11770 JSBigFloat *p;
11748 p = js_mallocz(ctx, sizeof(*p));11771 p = js_malloc(ctx, sizeof(*p));
11749 if (!p)11772 if (!p)
11750 return NULL;11773 return NULL;
11751 p->header.ref_count = 1;11774 p->header.ref_count = 1;
@@ -11753,224 +11776,387 @@ static JSBigFloat *js_new_bf(JSContext *ctx) · 1 unmodified line
11753 return p;11776 return p;
11754}11777}
11755 11778
11756/* WARNING: 'a' is freed */11779static JSValue JS_NewBigFloat(JSContext *ctx)
11757static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a)
11758{11780{
11759 JSValue ret;
11760 JSBigFloat *p;11781 JSBigFloat *p;
11761 11782 p = js_malloc(ctx, sizeof(*p));
11762 p = js_new_bf(ctx);11783 if (!p)
11763 bf_memcpy(&p->num, a);11784 return JS_EXCEPTION;
11764 ret = JS_MKPTR(JS_TAG_BIG_FLOAT, p);11785 p->header.ref_count = 1;
11765 return ret;11786 bf_init(ctx->bf_ctx, &p->num);
11787 return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
11766}11788}
11767 11789
11768/* WARNING: 'a' is freed */11790static JSValue JS_NewBigDecimal(JSContext *ctx)
11769static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a)
11770{11791{
11771 JSValue ret;
11772 JSBigDecimal *p;11792 JSBigDecimal *p;
11773 11793 p = js_malloc(ctx, sizeof(*p));
11774 p = js_mallocz(ctx, sizeof(*p));
11775 if (!p)11794 if (!p)
11776 return JS_EXCEPTION;11795 return JS_EXCEPTION;
11777 p->header.ref_count = 1;11796 p->header.ref_count = 1;
11778 bfdec_init(ctx->bf_ctx, &p->num);11797 bfdec_init(ctx->bf_ctx, &p->num);
11779 bfdec_memcpy(&p->num, a);11798 return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
11780 ret = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
11781 return ret;
11782}11799}
11783 11800
11784/* WARNING: 'a' is freed */11801static JSValue JS_NewBigInt(JSContext *ctx)
11785static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint)
11786{11802{
11787 JSValue ret;
11788 JSBigFloat *p;11803 JSBigFloat *p;
11789 int32_t v;11804 p = js_malloc(ctx, sizeof(*p));
11790 11805 if (!p)
11791 if (!force_bigint && bf_get_int32(&v, a, 0) == 0) {11806 return JS_EXCEPTION;
11792 /* can fit in an int32 */11807 p->header.ref_count = 1;
11793 ret = JS_NewInt32(ctx, v);11808 bf_init(ctx->bf_ctx, &p->num);
11794 bf_delete(a);11809 return JS_MKPTR(JS_TAG_BIG_INT, p);
11795 } else {
11796 p = js_new_bf(ctx);
11797 bf_memcpy(&p->num, a);
11798 /* normalize the zero representation */
11799 if (bf_is_zero(&p->num))
11800 p->num.sign = 0;
11801 ret = JS_MKPTR(JS_TAG_BIG_INT, p);
11802 }
11803 return ret;
11804}11810}
11805 11811
11806static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a)11812static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
11813 BOOL convert_to_safe_integer)
11807{11814{
11808 return JS_NewBigInt2(ctx, a, !is_bigint_mode(ctx));11815 int64_t v;
11816 bf_t *a;
11817
11818 if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
11819 return val; /* fail safe */
11820 a = JS_GetBigInt(val);
11821 if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
11822 v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
11823 JS_FreeValue(ctx, val);
11824 return JS_NewInt64(ctx, v);
11825 } else if (a->expn == BF_EXP_ZERO && a->sign) {
11826 JSBigFloat *p = JS_VALUE_GET_PTR(val);
11827 assert(p->header.ref_count == 1);
11828 a->sign = 0;
11829 }
11830 return val;
11809}11831}
11810 11832
11811/* return < 0 if exception, 0 if overloading method, 1 if overloading11833/* Convert the big int to a safe integer if in math mode. normalize
11812 operator called */11834 the zero representation. Could also be used to convert the bigint
11813static __exception int js_call_binary_op_fallback(JSContext *ctx,11835 to a short bigint value. The reference count of the value must be
11814 JSValue *pret,11836 1. Cannot fail */
11815 JSValueConst op1,11837static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
11816 JSValueConst op2,11838{
11817 OPCodeEnum op)11839 return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
11818{11840}
11819 JSAtom op_name;11841
11820 JSValue method, ret, c1, c2;11842/* must be kept in sync with JSOverloadableOperatorEnum */
11821 BOOL bool_result, swap_op;11843static const char *js_overloadable_operator_names[JS_OVOP_COUNT] = {
11822 JSValueConst args[2];11844 "+",
11845 "-",
11846 "*",
11847 "/",
11848 "%",
11849 "**",
11850 "|",
11851 "&",
11852 "^",
11853 "<<",
11854 ">>",
11855 ">>>",
11856 "==",
11857 "<",
11858 "pos",
11859 "neg",
11860 "++",
11861 "--",
11862 "~",
11863};
11823 11864
11824 bool_result = FALSE;11865static int get_ovop_from_opcode(OPCodeEnum op)
11825 swap_op = FALSE;11866{
11826 c1 = JS_UNDEFINED;
11827 c2 = JS_UNDEFINED;
11828 switch(op) {11867 switch(op) {
11829 case OP_add:11868 case OP_add:
11830 op_name = JS_ATOM_Symbol_operatorAdd;11869 return JS_OVOP_ADD;
11831 break;
11832 case OP_sub:11870 case OP_sub:
11833 op_name = JS_ATOM_Symbol_operatorSub;11871 return JS_OVOP_SUB;
11834 break;
11835 case OP_mul:11872 case OP_mul:
11836 op_name = JS_ATOM_Symbol_operatorMul;11873 return JS_OVOP_MUL;
11837 break;
11838 case OP_div:11874 case OP_div:
11839 case OP_math_div:11875 return JS_OVOP_DIV;
11840 op_name = JS_ATOM_Symbol_operatorDiv;
11841 break;
11842 case OP_mod:11876 case OP_mod:
11843 op_name = JS_ATOM_Symbol_operatorMod;
11844 break;
11845 case OP_pow:
11846 case OP_math_pow:
11847 op_name = JS_ATOM_Symbol_operatorPow;
11848 break;
11849 case OP_math_mod:11877 case OP_math_mod:
11850 op_name = JS_ATOM_Symbol_operatorMathMod;11878 return JS_OVOP_MOD;
11851 break;11879 case OP_pow:
11852 case OP_shl:11880 return JS_OVOP_POW;
11853 op_name = JS_ATOM_Symbol_operatorShl;
11854 break;
11855 case OP_sar:
11856 op_name = JS_ATOM_Symbol_operatorShr;
11857 break;
11858 case OP_and:
11859 op_name = JS_ATOM_Symbol_operatorAnd;
11860 break;
11861 case OP_or:11881 case OP_or:
11862 op_name = JS_ATOM_Symbol_operatorOr;11882 return JS_OVOP_OR;
11863 break;11883 case OP_and:
11884 return JS_OVOP_AND;
11864 case OP_xor:11885 case OP_xor:
11865 op_name = JS_ATOM_Symbol_operatorXor;11886 return JS_OVOP_XOR;
11866 break;11887 case OP_shl:
11888 return JS_OVOP_SHL;
11889 case OP_sar:
11890 return JS_OVOP_SAR;
11891 case OP_shr:
11892 return JS_OVOP_SHR;
11893 case OP_eq:
11894 case OP_neq:
11895 return JS_OVOP_EQ;
11867 case OP_lt:11896 case OP_lt:
11868 op_name = JS_ATOM_Symbol_operatorCmpLT;
11869 bool_result = TRUE;
11870 break;
11871 case OP_lte:11897 case OP_lte:
11872 op_name = JS_ATOM_Symbol_operatorCmpLE;
11873 bool_result = TRUE;
11874 break;
11875 case OP_gt:11898 case OP_gt:
11876 op_name = JS_ATOM_Symbol_operatorCmpLT;
11877 bool_result = TRUE;
11878 swap_op = TRUE;
11879 break;
11880 case OP_gte:11899 case OP_gte:
11881 op_name = JS_ATOM_Symbol_operatorCmpLE;11900 return JS_OVOP_LESS;
11882 bool_result = TRUE;11901 case OP_plus:
11883 swap_op = TRUE;11902 return JS_OVOP_POS;
11884 break;11903 case OP_neg:
11885 case OP_eq:11904 return JS_OVOP_NEG;
11886 case OP_neq:11905 case OP_inc:
11887 op_name = JS_ATOM_Symbol_operatorCmpEQ;11906 return JS_OVOP_INC;
11888 bool_result = TRUE;11907 case OP_dec:
11889 break;11908 return JS_OVOP_DEC;
11890 default:11909 default:
11891 goto fail;11910 abort();
11911 }
11912}
11913
11914/* return NULL if not present */
11915static JSObject *find_binary_op(JSBinaryOperatorDef *def,
11916 uint32_t operator_index,
11917 JSOverloadableOperatorEnum op)
11918{
11919 JSBinaryOperatorDefEntry *ent;
11920 int i;
11921 for(i = 0; i < def->count; i++) {
11922 ent = &def->tab[i];
11923 if (ent->operator_index == operator_index)
11924 return ent->ops[op];
11892 }11925 }
11893 c1 = JS_GetProperty(ctx, op1, JS_ATOM_constructor);11926 return NULL;
11894 if (JS_IsException(c1))11927}
11928
11929/* return -1 if exception, 0 if no operator overloading, 1 if
11930 overloaded operator called */
11931static __exception int js_call_binary_op_fallback(JSContext *ctx,
11932 JSValue *pret,
11933 JSValueConst op1,
11934 JSValueConst op2,
11935 OPCodeEnum op,
11936 BOOL is_numeric,
11937 int hint)
11938{
11939 JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
11940 JSOperatorSetData *opset1, *opset2;
11941 JSOverloadableOperatorEnum ovop;
11942 JSObject *p;
11943 JSValueConst args[2];
11944
11945 if (!ctx->allow_operator_overloading)
11946 return 0;
11947
11948 opset2_obj = JS_UNDEFINED;
11949 opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
11950 if (JS_IsException(opset1_obj))
11895 goto exception;11951 goto exception;
11896 c2 = JS_GetProperty(ctx, op2, JS_ATOM_constructor);11952 if (JS_IsUndefined(opset1_obj))
11897 if (JS_IsException(c2))11953 return 0;
11954 opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
11955 if (!opset1)
11898 goto exception;11956 goto exception;
11899 if (JS_VALUE_GET_TAG(c1) != JS_TAG_OBJECT ||11957
11900 JS_VALUE_GET_TAG(c2) != JS_TAG_OBJECT)11958 opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
11901 goto fail;11959 if (JS_IsException(opset2_obj))
11902 if (JS_VALUE_GET_OBJ(c1) == JS_VALUE_GET_OBJ(c2)) {11960 goto exception;
11903 /* if same constructor, there is no ambiguity */11961 if (JS_IsUndefined(opset2_obj)) {
11904 method = JS_GetProperty(ctx, c1, op_name);11962 JS_FreeValue(ctx, opset1_obj);
11963 return 0;
11964 }
11965 opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
11966 if (!opset2)
11967 goto exception;
11968
11969 if (opset1->is_primitive && opset2->is_primitive) {
11970 JS_FreeValue(ctx, opset1_obj);
11971 JS_FreeValue(ctx, opset2_obj);
11972 return 0;
11973 }
11974
11975 ovop = get_ovop_from_opcode(op);
11976
11977 if (opset1->operator_counter == opset2->operator_counter) {
11978 p = opset1->self_ops[ovop];
11979 } else if (opset1->operator_counter > opset2->operator_counter) {
11980 p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
11905 } else {11981 } else {
11906 JSValue val;11982 p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
11907 int order1, order2;11983 }
11984 if (!p) {
11985 JS_ThrowTypeError(ctx, "operator %s: no function defined",
11986 js_overloadable_operator_names[ovop]);
11987 goto exception;
11988 }
11908 11989
11909 /* different constructors: we use a user-defined ordering */11990 if (opset1->is_primitive) {
11910 val = JS_GetProperty(ctx, c1, JS_ATOM_Symbol_operatorOrder);11991 if (is_numeric) {
11911 if (JS_IsException(val))11992 new_op1 = JS_ToNumeric(ctx, op1);
11912 goto exception;11993 } else {
11913 if (JS_IsUndefined(val))11994 new_op1 = JS_ToPrimitive(ctx, op1, hint);
11914 goto undef_order;
11915 if (JS_ToInt32Free(ctx, &order1, val))
11916 goto exception;
11917 val = JS_GetProperty(ctx, c2, JS_ATOM_Symbol_operatorOrder);
11918 if (JS_IsException(val))
11919 goto exception;
11920 if (JS_IsUndefined(val)) {
11921 undef_order:
11922 JS_FreeValue(ctx, c1);
11923 JS_FreeValue(ctx, c2);
11924 *pret = JS_UNDEFINED;
11925 return 0;
11926 }11995 }
11927 if (JS_ToInt32Free(ctx, &order2, val))11996 if (JS_IsException(new_op1))
11928 goto exception;11997 goto exception;
11929 /* ambiguous priority: error */11998 } else {
11930 if (order1 == order2) {11999 new_op1 = JS_DupValue(ctx, op1);
11931 JS_ThrowTypeError(ctx, "operator_order is identical in both constructors");12000 }
11932 goto exception;12001
11933 }12002 if (opset2->is_primitive) {
11934 if (order1 > order2) {12003 if (is_numeric) {
11935 val = c1;12004 new_op2 = JS_ToNumeric(ctx, op2);
11936 } else {12005 } else {
11937 val = c2;12006 new_op2 = JS_ToPrimitive(ctx, op2, hint);
11938 }12007 }
11939 method = JS_GetProperty(ctx, val, op_name);12008 if (JS_IsException(new_op2)) {
11940 }12009 JS_FreeValue(ctx, new_op1);
11941 JS_FreeValue(ctx, c1);12010 goto exception;
11942 JS_FreeValue(ctx, c2);12011 }
11943 c1 = JS_UNDEFINED;12012 } else {
11944 c2 = JS_UNDEFINED;12013 new_op2 = JS_DupValue(ctx, op2);
11945 if (JS_IsException(method))
11946 goto exception;
11947 if (JS_IsUndefined(method) || JS_IsNull(method)) {
11948 *pret = JS_UNDEFINED;
11949 return 0;
11950 }12014 }
11951 if (swap_op) {12015
11952 args[0] = op2;12016 /* XXX: could apply JS_ToPrimitive() if primitive type so that the
11953 args[1] = op1;12017 operator function does not get a value object */
12018
12019 method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12020 if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
12021 args[0] = new_op2;
12022 args[1] = new_op1;
11954 } else {12023 } else {
11955 args[0] = op1;12024 args[0] = new_op1;
11956 args[1] = op2;12025 args[1] = new_op2;
11957 }12026 }
11958 ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);12027 ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12028 JS_FreeValue(ctx, new_op1);
12029 JS_FreeValue(ctx, new_op2);
11959 if (JS_IsException(ret))12030 if (JS_IsException(ret))
11960 goto exception;12031 goto exception;
11961 if (bool_result) {12032 if (ovop == JS_OVOP_EQ) {
11962 BOOL res = JS_ToBoolFree(ctx, ret);12033 BOOL res = JS_ToBoolFree(ctx, ret);
11963 if (op == OP_neq)12034 if (op == OP_neq)
11964 res ^= 1;12035 res ^= 1;
11965 ret = JS_NewBool(ctx, res);12036 ret = JS_NewBool(ctx, res);
12037 } else if (ovop == JS_OVOP_LESS) {
12038 if (JS_IsUndefined(ret)) {
12039 ret = JS_FALSE;
12040 } else {
12041 BOOL res = JS_ToBoolFree(ctx, ret);
12042 if (op == OP_lte || op == OP_gte)
12043 res ^= 1;
12044 ret = JS_NewBool(ctx, res);
12045 }
11966 }12046 }
12047 JS_FreeValue(ctx, opset1_obj);
12048 JS_FreeValue(ctx, opset2_obj);
11967 *pret = ret;12049 *pret = ret;
11968 return 1;12050 return 1;
11969 fail:
11970 JS_ThrowTypeError(ctx, "invalid types for binary operator");
11971 exception:12051 exception:
11972 JS_FreeValue(ctx, c1);12052 JS_FreeValue(ctx, opset1_obj);
11973 JS_FreeValue(ctx, c2);12053 JS_FreeValue(ctx, opset2_obj);
12054 *pret = JS_UNDEFINED;
12055 return -1;
12056}
12057
12058/* try to call the operation on the operatorSet field of 'obj'. Only
12059 used for "/" and "**" on the BigInt prototype in math mode */
12060static __exception int js_call_binary_op_simple(JSContext *ctx,
12061 JSValue *pret,
12062 JSValueConst obj,
12063 JSValueConst op1,
12064 JSValueConst op2,
12065 OPCodeEnum op)
12066{
12067 JSValue opset1_obj, method, ret, new_op1, new_op2;
12068 JSOperatorSetData *opset1;
12069 JSOverloadableOperatorEnum ovop;
12070 JSObject *p;
12071 JSValueConst args[2];
12072
12073 opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
12074 if (JS_IsException(opset1_obj))
12075 goto exception;
12076 if (JS_IsUndefined(opset1_obj))
12077 return 0;
12078 opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12079 if (!opset1)
12080 goto exception;
12081 ovop = get_ovop_from_opcode(op);
12082
12083 p = opset1->self_ops[ovop];
12084 if (!p) {
12085 JS_FreeValue(ctx, opset1_obj);
12086 return 0;
12087 }
12088
12089 new_op1 = JS_ToNumeric(ctx, op1);
12090 if (JS_IsException(new_op1))
12091 goto exception;
12092 new_op2 = JS_ToNumeric(ctx, op2);
12093 if (JS_IsException(new_op2)) {
12094 JS_FreeValue(ctx, new_op1);
12095 goto exception;
12096 }
12097
12098 method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12099 args[0] = new_op1;
12100 args[1] = new_op2;
12101 ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12102 JS_FreeValue(ctx, new_op1);
12103 JS_FreeValue(ctx, new_op2);
12104 if (JS_IsException(ret))
12105 goto exception;
12106 JS_FreeValue(ctx, opset1_obj);
12107 *pret = ret;
12108 return 1;
12109 exception:
12110 JS_FreeValue(ctx, opset1_obj);
12111 *pret = JS_UNDEFINED;
12112 return -1;
12113}
12114
12115/* return -1 if exception, 0 if no operator overloading, 1 if
12116 overloaded operator called */
12117static __exception int js_call_unary_op_fallback(JSContext *ctx,
12118 JSValue *pret,
12119 JSValueConst op1,
12120 OPCodeEnum op)
12121{
12122 JSValue opset1_obj, method, ret;
12123 JSOperatorSetData *opset1;
12124 JSOverloadableOperatorEnum ovop;
12125 JSObject *p;
12126
12127 if (!ctx->allow_operator_overloading)
12128 return 0;
12129
12130 opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12131 if (JS_IsException(opset1_obj))
12132 goto exception;
12133 if (JS_IsUndefined(opset1_obj))
12134 return 0;
12135 opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12136 if (!opset1)
12137 goto exception;
12138 if (opset1->is_primitive) {
12139 JS_FreeValue(ctx, opset1_obj);
12140 return 0;
12141 }
12142
12143 ovop = get_ovop_from_opcode(op);
12144
12145 p = opset1->self_ops[ovop];
12146 if (!p) {
12147 JS_ThrowTypeError(ctx, "no overloaded operator %s",
12148 js_overloadable_operator_names[ovop]);
12149 goto exception;
12150 }
12151 method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12152 ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
12153 if (JS_IsException(ret))
12154 goto exception;
12155 JS_FreeValue(ctx, opset1_obj);
12156 *pret = ret;
12157 return 1;
12158 exception:
12159 JS_FreeValue(ctx, opset1_obj);
11974 *pret = JS_UNDEFINED;12160 *pret = JS_UNDEFINED;
11975 return -1;12161 return -1;
11976}12162}
@@ -11993,16 +12179,22 @@ static JSValue throw_bf_exception(JSContext *ctx, int status) · 16 unmodified lines
11993static int js_unary_arith_bigint(JSContext *ctx,12179static int js_unary_arith_bigint(JSContext *ctx,
11994 JSValue *pres, OPCodeEnum op, JSValue op1)12180 JSValue *pres, OPCodeEnum op, JSValue op1)
11995{12181{
11996 bf_t a_s, r_s, *r = &r_s, *a;12182 bf_t a_s, *r, *a;
11997 int ret, v;12183 int ret, v;
12184 JSValue res;
11998 12185
11999 if (op == OP_plus && !is_bigint_mode(ctx)) {12186 if (op == OP_plus && !is_math_mode(ctx)) {
12000 JS_ThrowTypeError(ctx, "bigint argument with unary +");12187 JS_ThrowTypeError(ctx, "bigint argument with unary +");
12001 JS_FreeValue(ctx, op1);12188 JS_FreeValue(ctx, op1);
12002 return -1;12189 return -1;
12003 }12190 }
12191 res = JS_NewBigInt(ctx);
12192 if (JS_IsException(res)) {
12193 JS_FreeValue(ctx, op1);
12194 return -1;
12195 }
12196 r = JS_GetBigInt(res);
12004 a = JS_ToBigInt(ctx, &a_s, op1);12197 a = JS_ToBigInt(ctx, &a_s, op1);
12005 bf_init(ctx->bf_ctx, r);
12006 ret = 0;12198 ret = 0;
12007 switch(op) {12199 switch(op) {
12008 case OP_inc:12200 case OP_inc:
@@ -12027,28 +12219,35 @@ static int js_unary_arith_bigint(JSContext *ctx, · 18 unmodified lines
12027 JS_FreeBigInt(ctx, a, &a_s);12219 JS_FreeBigInt(ctx, a, &a_s);
12028 JS_FreeValue(ctx, op1);12220 JS_FreeValue(ctx, op1);
12029 if (unlikely(ret)) {12221 if (unlikely(ret)) {
12030 bf_delete(r);12222 JS_FreeValue(ctx, res);
12031 throw_bf_exception(ctx, ret);12223 throw_bf_exception(ctx, ret);
12032 return -1;12224 return -1;
12033 }12225 }
12034 *pres = JS_NewBigInt(ctx, r);12226 res = JS_CompactBigInt(ctx, res);
12227 *pres = res;
12035 return 0;12228 return 0;
12036}12229}
12037 12230
12038static int js_unary_arith_bigfloat(JSContext *ctx,12231static int js_unary_arith_bigfloat(JSContext *ctx,
12039 JSValue *pres, OPCodeEnum op, JSValue op1)12232 JSValue *pres, OPCodeEnum op, JSValue op1)
12040{12233{
12041 bf_t a_s, r_s, *r = &r_s, *a;12234 bf_t a_s, *r, *a;
12042 int ret, v;12235 int ret, v;
12236 JSValue res;
12043 12237
12044 if (op == OP_plus && !is_bigint_mode(ctx)) {12238 if (op == OP_plus && !is_math_mode(ctx)) {
12045 JS_ThrowTypeError(ctx, "bigfloat argument with unary +");12239 JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
12046 JS_FreeValue(ctx, op1);12240 JS_FreeValue(ctx, op1);
12047 return -1;12241 return -1;
12048 }12242 }
12049 12243
12244 res = JS_NewBigFloat(ctx);
12245 if (JS_IsException(res)) {
12246 JS_FreeValue(ctx, op1);
12247 return -1;
12248 }
12249 r = JS_GetBigFloat(res);
12050 a = JS_ToBigFloat(ctx, &a_s, op1);12250 a = JS_ToBigFloat(ctx, &a_s, op1);
12051 bf_init(ctx->bf_ctx, r);
12052 ret = 0;12251 ret = 0;
12053 switch(op) {12252 switch(op) {
12054 case OP_inc:12253 case OP_inc:
@@ -12070,28 +12269,34 @@ static int js_unary_arith_bigfloat(JSContext *ctx, · 15 unmodified lines
12070 bf_delete(a);12269 bf_delete(a);
12071 JS_FreeValue(ctx, op1);12270 JS_FreeValue(ctx, op1);
12072 if (unlikely(ret & BF_ST_MEM_ERROR)) {12271 if (unlikely(ret & BF_ST_MEM_ERROR)) {
12073 bf_delete(r);12272 JS_FreeValue(ctx, res);
12074 throw_bf_exception(ctx, ret);12273 throw_bf_exception(ctx, ret);
12075 return -1;12274 return -1;
12076 }12275 }
12077 *pres = JS_NewBigFloat(ctx, r);12276 *pres = res;
12078 return 0;12277 return 0;
12079}12278}
12080 12279
12081static int js_unary_arith_bigdecimal(JSContext *ctx,12280static int js_unary_arith_bigdecimal(JSContext *ctx,
12082 JSValue *pres, OPCodeEnum op, JSValue op1)12281 JSValue *pres, OPCodeEnum op, JSValue op1)
12083{12282{
12084 bfdec_t r_s, *r = &r_s, *a;12283 bfdec_t *r, *a;
12085 int ret, v;12284 int ret, v;
12086 12285 JSValue res;
12087 if (op == OP_plus && !is_bigint_mode(ctx)) {12286
12287 if (op == OP_plus && !is_math_mode(ctx)) {
12088 JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");12288 JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
12089 JS_FreeValue(ctx, op1);12289 JS_FreeValue(ctx, op1);
12090 return -1;12290 return -1;
12091 }12291 }
12092 12292
12293 res = JS_NewBigDecimal(ctx);
12294 if (JS_IsException(res)) {
12295 JS_FreeValue(ctx, op1);
12296 return -1;
12297 }
12298 r = JS_GetBigDecimal(res);
12093 a = JS_ToBigDecimal(ctx, op1);12299 a = JS_ToBigDecimal(ctx, op1);
12094 bfdec_init(ctx->bf_ctx, r);
12095 ret = 0;12300 ret = 0;
12096 switch(op) {12301 switch(op) {
12097 case OP_inc:12302 case OP_inc:
@@ -12111,11 +12316,11 @@ static int js_unary_arith_bigdecimal(JSContext *ctx, · 13 unmodified lines
12111 }12316 }
12112 JS_FreeValue(ctx, op1);12317 JS_FreeValue(ctx, op1);
12113 if (unlikely(ret)) {12318 if (unlikely(ret)) {
12114 bfdec_delete(r);12319 JS_FreeValue(ctx, res);
12115 throw_bf_exception(ctx, ret);12320 throw_bf_exception(ctx, ret);
12116 return -1;12321 return -1;
12117 }12322 }
12118 *pres = JS_NewBigDecimal(ctx, r);12323 *pres = res;
12119 return 0;12324 return 0;
12120}12325}
12121 12326
@@ -12123,112 +12328,93 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, · 1 unmodified line
12123 JSValue *sp,12328 JSValue *sp,
12124 OPCodeEnum op)12329 OPCodeEnum op)
12125{12330{
12126 JSValue op1, val, method;12331 JSValue op1, val;
12127 BOOL is_legacy;12332 int v, ret;
12128 JSAtom op_name;
12129 int v;
12130 uint32_t tag;12333 uint32_t tag;
12131 12334
12132 op1 = sp[-1];12335 op1 = sp[-1];
12133 /* fast path for float64 */12336 /* fast path for float64 */
12134 if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))12337 if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
12135 goto handle_float64;12338 goto handle_float64;
12136 if (JS_IsObject(op1) && ctx->bignum_ext) {12339 if (JS_IsObject(op1)) {
12137 switch(op) {12340 ret = js_call_unary_op_fallback(ctx, &val, op1, op);
12138 case OP_plus:12341 if (ret < 0)
12139 op_name = JS_ATOM_Symbol_operatorPlus;
12140 break;
12141 case OP_neg:
12142 op_name = JS_ATOM_Symbol_operatorNeg;
12143 break;
12144 case OP_inc:
12145 op_name = JS_ATOM_Symbol_operatorInc;
12146 break;
12147 case OP_dec:
12148 op_name = JS_ATOM_Symbol_operatorDec;
12149 break;
12150 default:
12151 abort();
12152 }
12153 method = JS_GetProperty(ctx, op1, op_name);
12154 if (JS_IsException(method))
12155 return -1;
12156 if (JS_IsUndefined(method) || JS_IsNull(method))
12157 goto to_number;
12158 val = JS_CallFree(ctx, method, op1, 0, NULL);
12159 if (JS_IsException(val))
12160 return -1;12342 return -1;
12161 JS_FreeValue(ctx, op1);12343 if (ret) {
12162 sp[-1] = val;12344 JS_FreeValue(ctx, op1);
12163 } else {12345 sp[-1] = val;
12164 to_number:12346 return 0;
12165 op1 = JS_ToNumericFree(ctx, op1);12347 }
12166 if (JS_IsException(op1))12348 }
12167 goto exception;12349
12168 is_legacy = is_bigint_mode(ctx) ^ 1;12350 op1 = JS_ToNumericFree(ctx, op1);
12169 tag = JS_VALUE_GET_TAG(op1);12351 if (JS_IsException(op1))
12170 switch(tag) {12352 goto exception;
12171 case JS_TAG_INT:12353 tag = JS_VALUE_GET_TAG(op1);
12172 {12354 switch(tag) {
12173 int64_t v64;12355 case JS_TAG_INT:
12174 v64 = JS_VALUE_GET_INT(op1);12356 {
12175 switch(op) {12357 int64_t v64;
12176 case OP_inc:12358 v64 = JS_VALUE_GET_INT(op1);
12177 case OP_dec:12359 switch(op) {
12178 v = 2 * (op - OP_dec) - 1;12360 case OP_inc:
12179 v64 += v;12361 case OP_dec:
12180 break;12362 v = 2 * (op - OP_dec) - 1;
12181 case OP_plus:12363 v64 += v;
12182 break;12364 break;
12183 case OP_neg:12365 case OP_plus:
12184 if (v64 == 0 && is_legacy) {12366 break;
12185 sp[-1] = __JS_NewFloat64(ctx, -0.0);12367 case OP_neg:
12186 return 0;12368 if (v64 == 0) {
12187 } else {12369 sp[-1] = __JS_NewFloat64(ctx, -0.0);
12188 v64 = -v64;12370 return 0;
12189 }12371 } else {
12190 break;12372 v64 = -v64;
12191 default:
12192 abort();
12193 }12373 }
12194 sp[-1] = JS_NewInt64(ctx, v64);12374 break;
12375 default:
12376 abort();
12195 }12377 }
12196 break;12378 sp[-1] = JS_NewInt64(ctx, v64);
12197 case JS_TAG_BIG_INT:12379 }
12198 if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))12380 break;
12199 goto exception;12381 case JS_TAG_BIG_INT:
12200 break;12382 handle_bigint:
12201 case JS_TAG_BIG_FLOAT:12383 if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
12202 if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))12384 goto exception;
12203 goto exception;12385 break;
12204 break;12386 case JS_TAG_BIG_FLOAT:
12205 case JS_TAG_BIG_DECIMAL:12387 if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
12206 if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))12388 goto exception;
12207 goto exception;12389 break;
12208 break;12390 case JS_TAG_BIG_DECIMAL:
12209 default:12391 if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
12210 handle_float64:12392 goto exception;
12211 {12393 break;
12212 double d;12394 default:
12213 d = JS_VALUE_GET_FLOAT64(op1);12395 handle_float64:
12214 switch(op) {12396 {
12215 case OP_inc:12397 double d;
12216 case OP_dec:12398 if (is_math_mode(ctx))
12217 v = 2 * (op - OP_dec) - 1;12399 goto handle_bigint;
12218 d += v;12400 d = JS_VALUE_GET_FLOAT64(op1);
12219 break;12401 switch(op) {
12220 case OP_plus:12402 case OP_inc:
12221 break;12403 case OP_dec:
12222 case OP_neg:12404 v = 2 * (op - OP_dec) - 1;
12223 d = -d;12405 d += v;
12224 break;12406 break;
12225 default:12407 case OP_plus:
12226 abort();12408 break;
12227 }12409 case OP_neg:
12228 sp[-1] = __JS_NewFloat64(ctx, d);12410 d = -d;
12411 break;
12412 default:
12413 abort();
12229 }12414 }
12230 break;12415 sp[-1] = __JS_NewFloat64(ctx, d);
12231 }12416 }
12417 break;
12232 }12418 }
12233 return 0;12419 return 0;
12234 exception:12420 exception:
@@ -12255,39 +12441,33 @@ static __exception int js_post_inc_slow(JSContext *ctx, · 20 unmodified lines
12255 12441
12256static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)12442static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
12257{12443{
12258 JSValue op1, method, val;12444 JSValue op1, val;
12259 12445 int ret;
12446
12260 op1 = sp[-1];12447 op1 = sp[-1];
12261 if (JS_IsObject(op1)) {12448 if (JS_IsObject(op1)) {
12262 if (!ctx->bignum_ext)12449 ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
12263 goto to_number;12450 if (ret < 0)
12264 method = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorNot);
12265 if (JS_IsException(method))
12266 return -1;
12267 if (JS_IsUndefined(method) || JS_IsNull(method))
12268 goto to_number;
12269 val = JS_CallFree(ctx, method, op1, 0, NULL);
12270 if (JS_IsException(val))
12271 return -1;12451 return -1;
12272 JS_FreeValue(ctx, op1);12452 if (ret) {
12273 sp[-1] = val;12453 JS_FreeValue(ctx, op1);
12274 } else {12454 sp[-1] = val;
12275 if (JS_IsString(op1)) {12455 return 0;
12276 to_number:
12277 op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);
12278 if (JS_IsException(op1))
12279 goto exception;
12280 }
12281 if (is_bigint_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12282 if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12283 goto exception;
12284 } else {
12285 int32_t v1;
12286 if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12287 goto exception;
12288 sp[-1] = JS_NewInt32(ctx, ~v1);
12289 }12456 }
12290 }12457 }
12458
12459 op1 = JS_ToNumericFree(ctx, op1);
12460 if (JS_IsException(op1))
12461 goto exception;
12462 if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12463 if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12464 goto exception;
12465 } else {
12466 int32_t v1;
12467 if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12468 goto exception;
12469 sp[-1] = JS_NewInt32(ctx, ~v1);
12470 }
12291 return 0;12471 return 0;
12292 exception:12472 exception:
12293 sp[-1] = JS_UNDEFINED;12473 sp[-1] = JS_UNDEFINED;
@@ -12297,12 +12477,19 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) · 3 unmodified lines
12297static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,12477static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
12298 JSValue *pres, JSValue op1, JSValue op2)12478 JSValue *pres, JSValue op1, JSValue op2)
12299{12479{
12300 bf_t a_s, b_s, r_s, *r, *a, *b;12480 bf_t a_s, b_s, *r, *a, *b;
12301 int ret, rnd_mode;12481 int ret;
12482 JSValue res;
12302 12483
12484 res = JS_NewBigFloat(ctx);
12485 if (JS_IsException(res)) {
12486 JS_FreeValue(ctx, op1);
12487 JS_FreeValue(ctx, op2);
12488 return -1;
12489 }
12490 r = JS_GetBigFloat(res);
12303 a = JS_ToBigFloat(ctx, &a_s, op1);12491 a = JS_ToBigFloat(ctx, &a_s, op1);
12304 b = JS_ToBigFloat(ctx, &b_s, op2);12492 b = JS_ToBigFloat(ctx, &b_s, op2);
12305 r = &r_s;
12306 bf_init(ctx->bf_ctx, r);12493 bf_init(ctx->bf_ctx, r);
12307 switch(op) {12494 switch(op) {
12308 case OP_add:12495 case OP_add:
@@ -12314,29 +12501,21 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
12314 case OP_mul:12501 case OP_mul:
12315 ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);12502 ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
12316 break;12503 break;
12317 case OP_math_div:
12318 case OP_div:12504 case OP_div:
12319 ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);12505 ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
12320 break;12506 break;
12321 case OP_math_mod:12507 case OP_math_mod:
12322 /* Euclidian remainder */12508 /* Euclidian remainder */
12323 rnd_mode = BF_DIVREM_EUCLIDIAN;12509 ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12324 goto do_mod;12510 BF_DIVREM_EUCLIDIAN);
12511 break;
12325 case OP_mod:12512 case OP_mod:
12326 rnd_mode = BF_RNDZ;12513 ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12327 do_mod:12514 BF_RNDZ);
12328 {
12329 bf_t q_s, *q = &q_s;
12330 bf_init(ctx->bf_ctx, q);
12331 ret = bf_divrem(q, r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12332 rnd_mode);
12333 bf_delete(q);
12334 }
12335 break;12515 break;
12336 case OP_pow:12516 case OP_pow:
12337 case OP_math_pow:
12338 ret = bf_pow(r, a, b, ctx->fp_env.prec,12517 ret = bf_pow(r, a, b, ctx->fp_env.prec,
12339 ctx->fp_env.flags | BF_POW_JS_QUICKS);12518 ctx->fp_env.flags | BF_POW_JS_QUIRKS);
12340 break;12519 break;
12341 default:12520 default:
12342 abort();12521 abort();
@@ -12348,21 +12527,24 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
12348 JS_FreeValue(ctx, op1);12527 JS_FreeValue(ctx, op1);
12349 JS_FreeValue(ctx, op2);12528 JS_FreeValue(ctx, op2);
12350 if (unlikely(ret & BF_ST_MEM_ERROR)) {12529 if (unlikely(ret & BF_ST_MEM_ERROR)) {
12351 bf_delete(r);12530 JS_FreeValue(ctx, res);
12352 throw_bf_exception(ctx, ret);12531 throw_bf_exception(ctx, ret);
12353 return -1;12532 return -1;
12354 }12533 }
12355 *pres = JS_NewBigFloat(ctx, r);12534 *pres = res;
12356 return 0;12535 return 0;
12357}12536}
12358 12537
12359static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,12538static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
12360 JSValue *pres, JSValue op1, JSValue op2)12539 JSValue *pres, JSValue op1, JSValue op2)
12361{12540{
12362 bf_t a_s, b_s, r_s, *r, *a, *b;12541 bf_t a_s, b_s, *r, *a, *b;
12363 int ret, rnd_mode;12542 int ret;
12364 JSValue res;12543 JSValue res;
12365 12544
12545 res = JS_NewBigInt(ctx);
12546 if (JS_IsException(res))
12547 goto fail;
12366 a = JS_ToBigInt(ctx, &a_s, op1);12548 a = JS_ToBigInt(ctx, &a_s, op1);
12367 if (!a)12549 if (!a)
12368 goto fail;12550 goto fail;
@@ -12371,8 +12553,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 2 unmodified lines
12371 JS_FreeBigInt(ctx, a, &a_s);12553 JS_FreeBigInt(ctx, a, &a_s);
12372 goto fail;12554 goto fail;
12373 }12555 }
12374 r = &r_s;12556 r = JS_GetBigInt(res);
12375 bf_init(ctx->bf_ctx, r);
12376 ret = 0;12557 ret = 0;
12377 switch(op) {12558 switch(op) {
12378 case OP_add:12559 case OP_add:
@@ -12384,73 +12565,75 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
12384 case OP_mul:12565 case OP_mul:
12385 ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);12566 ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
12386 break;12567 break;
12387 case OP_math_div:
12388 goto op_fallback;
12389 case OP_div:12568 case OP_div:
12390 if (!is_bigint_mode(ctx)) {12569 if (!is_math_mode(ctx)) {
12391 bf_t rem_s, *rem = &rem_s;12570 bf_t rem_s, *rem = &rem_s;
12392 bf_init(ctx->bf_ctx, rem);12571 bf_init(ctx->bf_ctx, rem);
12393 ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,12572 ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
12394 BF_RNDZ);12573 BF_RNDZ);
12395 bf_delete(rem);12574 bf_delete(rem);
12396 } else {12575 } else {
12397 bf_div(r, a, b, 53, bf_set_exp_bits(11) |12576 goto math_mode_div_pow;
12398 BF_RNDN | BF_FLAG_SUBNORMAL);
12399 goto float64_result;
12400 }12577 }
12401 break;12578 break;
12402 case OP_math_mod:12579 case OP_math_mod:
12403 /* Euclidian remainder */12580 /* Euclidian remainder */
12404 rnd_mode = BF_DIVREM_EUCLIDIAN;12581 ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
12405 goto do_int_mod;12582 BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
12583 break;
12406 case OP_mod:12584 case OP_mod:
12407 rnd_mode = BF_RNDZ;12585 ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
12408 do_int_mod:12586 BF_RNDZ) & BF_ST_INVALID_OP;
12409 {
12410 bf_t q_s, *q = &q_s;
12411 bf_init(ctx->bf_ctx, q);
12412 ret = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ,
12413 rnd_mode) & BF_ST_INVALID_OP;
12414 bf_delete(q);
12415 }
12416 break;12587 break;
12417 case OP_pow:12588 case OP_pow:
12418 case OP_math_pow:
12419 if (b->sign) {12589 if (b->sign) {
12420 if (!is_bigint_mode(ctx)) {12590 if (!is_math_mode(ctx)) {
12421 ret = BF_ST_INVALID_OP;12591 ret = BF_ST_INVALID_OP;
12422 } else if (op == OP_math_pow) {12592 } else {
12423 op_fallback:12593 math_mode_div_pow:
12424 bf_delete(r);12594 JS_FreeValue(ctx, res);
12595 ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
12596 if (ret != 0) {
12597 JS_FreeBigInt(ctx, a, &a_s);
12598 JS_FreeBigInt(ctx, b, &b_s);
12599 JS_FreeValue(ctx, op1);
12600 JS_FreeValue(ctx, op2);
12601 if (ret < 0) {
12602 return -1;
12603 } else {
12604 *pres = res;
12605 return 0;
12606 }
12607 }
12608 /* if no BigInt power operator defined, return a
12609 bigfloat */
12610 res = JS_NewBigFloat(ctx);
12611 if (JS_IsException(res)) {
12612 JS_FreeBigInt(ctx, a, &a_s);
12613 JS_FreeBigInt(ctx, b, &b_s);
12614 goto fail;
12615 }
12616 r = JS_GetBigFloat(res);
12617 if (op == OP_div) {
12618 ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
12619 } else {
12620 ret = bf_pow(r, a, b, ctx->fp_env.prec,
12621 ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
12622 }
12425 JS_FreeBigInt(ctx, a, &a_s);12623 JS_FreeBigInt(ctx, a, &a_s);
12426 JS_FreeBigInt(ctx, b, &b_s);12624 JS_FreeBigInt(ctx, b, &b_s);
12427 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
12428 JS_FreeValue(ctx, op1);12625 JS_FreeValue(ctx, op1);
12429 JS_FreeValue(ctx, op2);12626 JS_FreeValue(ctx, op2);
12430 if (ret < 0) {12627 if (unlikely(ret)) {
12431 return -1;12628 JS_FreeValue(ctx, res);
12432 } else if (ret == 0) {12629 throw_bf_exception(ctx, ret);
12433 JS_ThrowTypeError(ctx, "operator must be defined for exact division or power");
12434 return -1;12630 return -1;
12435 }12631 }
12436 *pres = res;12632 *pres = res;
12437 return 0;12633 return 0;
12438 } else {
12439 double dr;
12440 bf_pow(r, a, b, 53, bf_set_exp_bits(11) |
12441 BF_RNDN | BF_FLAG_SUBNORMAL);
12442 float64_result:
12443 bf_get_float64(r, &dr, BF_RNDN);
12444 bf_delete(r);
12445 JS_FreeBigInt(ctx, a, &a_s);
12446 JS_FreeBigInt(ctx, b, &b_s);
12447 JS_FreeValue(ctx, op1);
12448 JS_FreeValue(ctx, op2);
12449 *pres = __JS_NewFloat64(ctx, dr);
12450 return 0;
12451 }12634 }
12452 } else {12635 } else {
12453 ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUICKS);12636 ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
12454 }12637 }
12455 break;12638 break;
12456 12639
@@ -12494,13 +12677,14 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 37 unmodified lines
12494 JS_FreeValue(ctx, op1);12677 JS_FreeValue(ctx, op1);
12495 JS_FreeValue(ctx, op2);12678 JS_FreeValue(ctx, op2);
12496 if (unlikely(ret)) {12679 if (unlikely(ret)) {
12497 bf_delete(r);12680 JS_FreeValue(ctx, res);
12498 throw_bf_exception(ctx, ret);12681 throw_bf_exception(ctx, ret);
12499 return -1;12682 return -1;
12500 }12683 }
12501 *pres = JS_NewBigInt(ctx, r);12684 *pres = JS_CompactBigInt(ctx, res);
12502 return 0;12685 return 0;
12503 fail:12686 fail:
12687 JS_FreeValue(ctx, res);
12504 JS_FreeValue(ctx, op1);12688 JS_FreeValue(ctx, op1);
12505 JS_FreeValue(ctx, op2);12689 JS_FreeValue(ctx, op2);
12506 return -1;12690 return -1;
@@ -12536,18 +12720,21 @@ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) · 29 unmodified lines
12536static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,12720static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
12537 JSValue *pres, JSValue op1, JSValue op2)12721 JSValue *pres, JSValue op1, JSValue op2)
12538{12722{
12539 bfdec_t r_s, *r, *a, *b;12723 bfdec_t *r, *a, *b;
12540 int ret, rnd_mode;12724 int ret;
12541 12725 JSValue res;
12542 /* big decimal result */12726
12727 res = JS_NewBigDecimal(ctx);
12728 if (JS_IsException(res))
12729 goto fail;
12730 r = JS_GetBigDecimal(res);
12731
12543 a = JS_ToBigDecimal(ctx, op1);12732 a = JS_ToBigDecimal(ctx, op1);
12544 if (!a)12733 if (!a)
12545 goto fail;12734 goto fail;
12546 b = JS_ToBigDecimal(ctx, op2);12735 b = JS_ToBigDecimal(ctx, op2);
12547 if (!b)12736 if (!b)
12548 goto fail;12737 goto fail;
12549 r = &r_s;
12550 bfdec_init(ctx->bf_ctx, r);
12551 switch(op) {12738 switch(op) {
12552 case OP_add:12739 case OP_add:
12553 ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);12740 ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
@@ -12558,26 +12745,17 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, · 4 unmodified lines
12558 case OP_mul:12745 case OP_mul:
12559 ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);12746 ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
12560 break;12747 break;
12561 case OP_math_div:
12562 case OP_div:12748 case OP_div:
12563 ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);12749 ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
12564 break;12750 break;
12565 case OP_math_mod:12751 case OP_math_mod:
12566 /* Euclidian remainder */12752 /* Euclidian remainder */
12567 rnd_mode = BF_DIVREM_EUCLIDIAN;12753 ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
12568 goto do_mod_dec;12754 break;
12569 case OP_mod:12755 case OP_mod:
12570 rnd_mode = BF_RNDZ;12756 ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
12571 do_mod_dec:
12572 {
12573 bfdec_t q_s, *q = &q_s;
12574 bfdec_init(ctx->bf_ctx, q);
12575 ret = bfdec_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, rnd_mode);
12576 bfdec_delete(q);
12577 }
12578 break;12757 break;
12579 case OP_pow:12758 case OP_pow:
12580 case OP_math_pow:
12581 ret = js_bfdec_pow(r, a, b);12759 ret = js_bfdec_pow(r, a, b);
12582 break;12760 break;
12583 default:12761 default:
@@ -12586,13 +12764,14 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, · 2 unmodified lines
12586 JS_FreeValue(ctx, op1);12764 JS_FreeValue(ctx, op1);
12587 JS_FreeValue(ctx, op2);12765 JS_FreeValue(ctx, op2);
12588 if (unlikely(ret)) {12766 if (unlikely(ret)) {
12589 bfdec_delete(r);12767 JS_FreeValue(ctx, res);
12590 throw_bf_exception(ctx, ret);12768 throw_bf_exception(ctx, ret);
12591 return -1;12769 return -1;
12592 }12770 }
12593 *pres = JS_NewBigDecimal(ctx, r);12771 *pres = res;
12594 return 0;12772 return 0;
12595 fail:12773 fail:
12774 JS_FreeValue(ctx, res);
12596 JS_FreeValue(ctx, op1);12775 JS_FreeValue(ctx, op1);
12597 JS_FreeValue(ctx, op2);12776 JS_FreeValue(ctx, op2);
12598 return -1;12777 return -1;
@@ -12602,7 +12781,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 3 unmodified lines
12602 OPCodeEnum op)12781 OPCodeEnum op)
12603{12782{
12604 JSValue op1, op2, res;12783 JSValue op1, op2, res;
12605 BOOL is_legacy;
12606 uint32_t tag1, tag2;12784 uint32_t tag1, tag2;
12607 int ret;12785 int ret;
12608 double d1, d2;12786 double d1, d2;
@@ -12619,12 +12797,11 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 10 unmodified lines
12619 }12797 }
12620 12798
12621 /* try to call an overloaded operator */12799 /* try to call an overloaded operator */
12622 if (((tag1 == JS_TAG_OBJECT &&12800 if ((tag1 == JS_TAG_OBJECT &&
12623 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||12801 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12624 (tag2 == JS_TAG_OBJECT &&12802 (tag2 == JS_TAG_OBJECT &&
12625 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&12803 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
12626 ctx->bignum_ext) {12804 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
12627 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
12628 if (ret != 0) {12805 if (ret != 0) {
12629 JS_FreeValue(ctx, op1);12806 JS_FreeValue(ctx, op1);
12630 JS_FreeValue(ctx, op2);12807 JS_FreeValue(ctx, op2);
@@ -12655,23 +12832,23 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 24 unmodified lines
12655 int64_t v;12832 int64_t v;
12656 v1 = JS_VALUE_GET_INT(op1);12833 v1 = JS_VALUE_GET_INT(op1);
12657 v2 = JS_VALUE_GET_INT(op2);12834 v2 = JS_VALUE_GET_INT(op2);
12658 is_legacy = is_bigint_mode(ctx) ^ 1;
12659 switch(op) {12835 switch(op) {
12660 case OP_sub:12836 case OP_sub:
12661 v = (int64_t)v1 - (int64_t)v2;12837 v = (int64_t)v1 - (int64_t)v2;
12662 break;12838 break;
12663 case OP_mul:12839 case OP_mul:
12664 v = (int64_t)v1 * (int64_t)v2;12840 v = (int64_t)v1 * (int64_t)v2;
12665 if (is_legacy && v == 0 && (v1 | v2) < 0) {12841 if (is_math_mode(ctx) &&
12842 (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
12843 goto handle_bigint;
12844 if (v == 0 && (v1 | v2) < 0) {
12666 sp[-2] = __JS_NewFloat64(ctx, -0.0);12845 sp[-2] = __JS_NewFloat64(ctx, -0.0);
12667 return 0;12846 return 0;
12668 }12847 }
12669 break;12848 break;
12670 case OP_math_div:
12671 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12672 goto exception;
12673 return 0;
12674 case OP_div:12849 case OP_div:
12850 if (is_math_mode(ctx))
12851 goto handle_bigint;
12675 sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);12852 sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
12676 return 0;12853 return 0;
12677 case OP_math_mod:12854 case OP_math_mod:
@@ -12688,26 +12865,19 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 10 unmodified lines
12688 }12865 }
12689 break;12866 break;
12690 case OP_mod:12867 case OP_mod:
12691 if (is_legacy && (v1 < 0 || v2 <= 0)) {12868 if (v1 < 0 || v2 <= 0) {
12692 sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));12869 sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
12693 return 0;12870 return 0;
12694 } else {12871 } else {
12695 if (unlikely(v2 == 0)) {
12696 throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
12697 goto exception;
12698 }
12699 v = (int64_t)v1 % (int64_t)v2;12872 v = (int64_t)v1 % (int64_t)v2;
12700 }12873 }
12701 break;12874 break;
12702 case OP_pow:12875 case OP_pow:
12703 case OP_math_pow:12876 if (!is_math_mode(ctx)) {
12704 if (is_legacy) {
12705 sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));12877 sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
12706 return 0;12878 return 0;
12707 } else {12879 } else {
12708 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))12880 goto handle_bigint;
12709 goto exception;
12710 return 0;
12711 }12881 }
12712 break;12882 break;
12713 default:12883 default:
@@ -12720,6 +12890,10 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 6 unmodified lines
12720 } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {12890 } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
12721 if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))12891 if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12722 goto exception;12892 goto exception;
12893 } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
12894 handle_bigint:
12895 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12896 goto exception;
12723 } else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) {12897 } else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) {
12724 double dr;12898 double dr;
12725 /* float64 result */12899 /* float64 result */
@@ -12730,6 +12904,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 4 unmodified lines
12730 if (JS_ToFloat64Free(ctx, &d2, op2))12904 if (JS_ToFloat64Free(ctx, &d2, op2))
12731 goto exception;12905 goto exception;
12732 handle_float64:12906 handle_float64:
12907 if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
12908 goto handle_bigint;
12733 switch(op) {12909 switch(op) {
12734 case OP_sub:12910 case OP_sub:
12735 dr = d1 - d2;12911 dr = d1 - d2;
@@ -12738,7 +12914,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 2 unmodified lines
12738 dr = d1 * d2;12914 dr = d1 * d2;
12739 break;12915 break;
12740 case OP_div:12916 case OP_div:
12741 case OP_math_div:
12742 dr = d1 / d2;12917 dr = d1 / d2;
12743 break;12918 break;
12744 case OP_mod:12919 case OP_mod:
@@ -12752,16 +12927,12 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 7 unmodified lines
12752 dr += d2;12927 dr += d2;
12753 break;12928 break;
12754 case OP_pow:12929 case OP_pow:
12755 case OP_math_pow:
12756 dr = js_pow(d1, d2);12930 dr = js_pow(d1, d2);
12757 break;12931 break;
12758 default:12932 default:
12759 abort();12933 abort();
12760 }12934 }
12761 sp[-2] = __JS_NewFloat64(ctx, dr);12935 sp[-2] = __JS_NewFloat64(ctx, dr);
12762 } else {
12763 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12764 goto exception;
12765 }12936 }
12766 return 0;12937 return 0;
12767 exception:12938 exception:
@@ -12792,12 +12963,14 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) · 24 unmodified lines
12792 12963
12793 if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {12964 if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
12794 /* try to call an overloaded operator */12965 /* try to call an overloaded operator */
12795 if (((tag1 == JS_TAG_OBJECT &&12966 if ((tag1 == JS_TAG_OBJECT &&
12796 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||12967 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
12797 (tag2 == JS_TAG_OBJECT &&12968 tag2 != JS_TAG_STRING)) ||
12798 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&12969 (tag2 == JS_TAG_OBJECT &&
12799 ctx->bignum_ext) {12970 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
12800 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add);12971 tag1 != JS_TAG_STRING))) {
12972 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
12973 FALSE, HINT_NONE);
12801 if (ret != 0) {12974 if (ret != 0) {
12802 JS_FreeValue(ctx, op1);12975 JS_FreeValue(ctx, op1);
12803 JS_FreeValue(ctx, op2);12976 JS_FreeValue(ctx, op2);
@@ -12886,6 +13059,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 82 unmodified lines
12886 JSValue op1, op2, res;13059 JSValue op1, op2, res;
12887 int ret;13060 int ret;
12888 uint32_t tag1, tag2;13061 uint32_t tag1, tag2;
13062 uint32_t v1, v2, r;
12889 13063
12890 op1 = sp[-2];13064 op1 = sp[-2];
12891 op2 = sp[-1];13065 op2 = sp[-1];
@@ -12893,12 +13067,11 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 1 unmodified line
12893 tag2 = JS_VALUE_GET_NORM_TAG(op2);13067 tag2 = JS_VALUE_GET_NORM_TAG(op2);
12894 13068
12895 /* try to call an overloaded operator */13069 /* try to call an overloaded operator */
12896 if (((tag1 == JS_TAG_OBJECT &&13070 if ((tag1 == JS_TAG_OBJECT &&
12897 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||13071 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12898 (tag2 == JS_TAG_OBJECT &&13072 (tag2 == JS_TAG_OBJECT &&
12899 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&13073 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
12900 ctx->bignum_ext) {13074 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
12901 ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
12902 if (ret != 0) {13075 if (ret != 0) {
12903 JS_FreeValue(ctx, op1);13076 JS_FreeValue(ctx, op1);
12904 JS_FreeValue(ctx, op2);13077 JS_FreeValue(ctx, op2);
@@ -12911,63 +13084,60 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 6 unmodified lines
12911 }13084 }
12912 }13085 }
12913 13086
12914 op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);13087 op1 = JS_ToNumericFree(ctx, op1);
12915 if (JS_IsException(op1)) {13088 if (JS_IsException(op1)) {
12916 JS_FreeValue(ctx, op2);13089 JS_FreeValue(ctx, op2);
12917 goto exception;13090 goto exception;
12918 }13091 }
12919 op2 = JS_ToNumberHintFree(ctx, op2, TON_FLAG_INTEGER);13092 op2 = JS_ToNumericFree(ctx, op2);
12920 if (JS_IsException(op2)) {13093 if (JS_IsException(op2)) {
12921 JS_FreeValue(ctx, op1);13094 JS_FreeValue(ctx, op1);
12922 goto exception;13095 goto exception;
12923 }13096 }
12924 13097
12925 if (!is_bigint_mode(ctx)) {13098 if (is_math_mode(ctx))
12926 uint32_t v1, v2, r;13099 goto bigint_op;
12927 13100
12928 tag1 = JS_VALUE_GET_TAG(op1);13101 tag1 = JS_VALUE_GET_TAG(op1);
12929 tag2 = JS_VALUE_GET_TAG(op2);13102 tag2 = JS_VALUE_GET_TAG(op2);
12930 if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {13103 if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
12931 if (tag1 != tag2) {13104 if (tag1 != tag2) {
12932 JS_FreeValue(ctx, op1);13105 JS_FreeValue(ctx, op1);
12933 JS_FreeValue(ctx, op2);13106 JS_FreeValue(ctx, op2);
12934 JS_ThrowTypeError(ctx, "both operands must be bigint");13107 JS_ThrowTypeError(ctx, "both operands must be bigint");
12935 goto exception;13108 goto exception;
12936 } else {
12937 goto bigint_op;
12938 }
12939 } else {13109 } else {
12940 if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {13110 bigint_op:
12941 JS_FreeValue(ctx, op2);13111 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12942 goto exception;
12943 }
12944 if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
12945 goto exception;13112 goto exception;
12946 switch(op) {
12947 case OP_shl:
12948 r = v1 << (v2 & 0x1f);
12949 break;
12950 case OP_sar:
12951 r = (int)v1 >> (v2 & 0x1f);
12952 break;
12953 case OP_and:
12954 r = v1 & v2;
12955 break;
12956 case OP_or:
12957 r = v1 | v2;
12958 break;
12959 case OP_xor:
12960 r = v1 ^ v2;
12961 break;
12962 default:
12963 abort();
12964 }
12965 sp[-2] = JS_NewInt32(ctx, r);
12966 }13113 }
12967 } else {13114 } else {
12968 bigint_op:13115 if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
12969 if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))13116 JS_FreeValue(ctx, op2);
13117 goto exception;
13118 }
13119 if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
12970 goto exception;13120 goto exception;
13121 switch(op) {
13122 case OP_shl:
13123 r = v1 << (v2 & 0x1f);
13124 break;
13125 case OP_sar:
13126 r = (int)v1 >> (v2 & 0x1f);
13127 break;
13128 case OP_and:
13129 r = v1 & v2;
13130 break;
13131 case OP_or:
13132 r = v1 | v2;
13133 break;
13134 case OP_xor:
13135 r = v1 ^ v2;
13136 break;
13137 default:
13138 abort();
13139 }
13140 sp[-2] = JS_NewInt32(ctx, r);
12971 }13141 }
12972 return 0;13142 return 0;
12973 exception:13143 exception:
@@ -13081,12 +13251,12 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 107 unmodified lines
13081 tag1 = JS_VALUE_GET_NORM_TAG(op1);13251 tag1 = JS_VALUE_GET_NORM_TAG(op1);
13082 tag2 = JS_VALUE_GET_NORM_TAG(op2);13252 tag2 = JS_VALUE_GET_NORM_TAG(op2);
13083 /* try to call an overloaded operator */13253 /* try to call an overloaded operator */
13084 if (((tag1 == JS_TAG_OBJECT &&13254 if ((tag1 == JS_TAG_OBJECT &&
13085 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||13255 (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13086 (tag2 == JS_TAG_OBJECT &&13256 (tag2 == JS_TAG_OBJECT &&
13087 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&13257 (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13088 ctx->bignum_ext) {13258 res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
13089 res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op);13259 FALSE, HINT_NUMBER);
13090 if (res != 0) {13260 if (res != 0) {
13091 JS_FreeValue(ctx, op1);13261 JS_FreeValue(ctx, op1);
13092 JS_FreeValue(ctx, op2);13262 JS_FreeValue(ctx, op2);
@@ -13165,7 +13335,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 72 unmodified lines
13165 } else {13335 } else {
13166 if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||13336 if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
13167 (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&13337 (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
13168 !is_bigint_mode(ctx)) {13338 !is_math_mode(ctx)) {
13169 if (tag1 == JS_TAG_STRING) {13339 if (tag1 == JS_TAG_STRING) {
13170 op1 = JS_StringToBigInt(ctx, op1);13340 op1 = JS_StringToBigInt(ctx, op1);
13171 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)13341 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13271,10 +13441,11 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 99 unmodified lines
13271 goto exception;13441 goto exception;
13272 }13442 }
13273 } else if (tag1 == tag2) {13443 } else if (tag1 == tag2) {
13274 if (tag1 == JS_TAG_OBJECT && ctx->bignum_ext) {13444 if (tag1 == JS_TAG_OBJECT) {
13275 /* try the fallback operator */13445 /* try the fallback operator */
13276 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,13446 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13277 is_neq ? OP_neq : OP_eq);13447 is_neq ? OP_neq : OP_eq,
13448 FALSE, HINT_NONE);
13278 if (res != 0) {13449 if (res != 0) {
13279 JS_FreeValue(ctx, op1);13450 JS_FreeValue(ctx, op1);
13280 JS_FreeValue(ctx, op2);13451 JS_FreeValue(ctx, op2);
@@ -13294,7 +13465,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 13 unmodified lines
13294 (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {13465 (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
13295 13466
13296 if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&13467 if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
13297 !is_bigint_mode(ctx)) {13468 !is_math_mode(ctx)) {
13298 if (tag1 == JS_TAG_STRING) {13469 if (tag1 == JS_TAG_STRING) {
13299 op1 = JS_StringToBigInt(ctx, op1);13470 op1 = JS_StringToBigInt(ctx, op1);
13300 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)13471 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13336,7 +13507,8 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 35 unmodified lines
13336 13507
13337 /* try the fallback operator */13508 /* try the fallback operator */
13338 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,13509 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13339 is_neq ? OP_neq : OP_eq);13510 is_neq ? OP_neq : OP_eq,
13511 FALSE, HINT_NONE);
13340 if (res != 0) {13512 if (res != 0) {
13341 JS_FreeValue(ctx, op1);13513 JS_FreeValue(ctx, op1);
13342 JS_FreeValue(ctx, op2);13514 JS_FreeValue(ctx, op2);
@@ -13391,7 +13563,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) · 48 unmodified lines
13391 goto exception;13563 goto exception;
13392 }13564 }
13393 /* XXX: could forbid >>> in bignum mode */13565 /* XXX: could forbid >>> in bignum mode */
13394 if (!is_bigint_mode(ctx) &&13566 if (!is_math_mode(ctx) &&
13395 (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||13567 (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
13396 JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {13568 JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
13397 JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");13569 JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
@@ -13433,34 +13605,38 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, · 35 unmodified lines
13433 13605
13434static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)13606static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
13435{13607{
13436 bf_t a_s, *a, r_s, *r = &r_s;13608 bf_t a_s, *a, *r;
13437 JSValue op1, op2;13609 JSValue op1, op2, res;
13438 slimb_t e;13610 int64_t e;
13439 int ret;13611 int ret;
13440 13612
13613 res = JS_NewBigFloat(ctx);
13614 if (JS_IsException(res))
13615 return -1;
13616 r = JS_GetBigFloat(res);
13441 op1 = sp[-2];13617 op1 = sp[-2];
13442 op2 = sp[-1];13618 op2 = sp[-1];
13443 a = JS_ToBigFloat(ctx, &a_s, op1);13619 a = JS_ToBigFloat(ctx, &a_s, op1);
13444 if (!a)13620 if (!a)
13445 return -1;13621 return -1;
13446#if LIMB_BITS == 3213622 if (JS_IsBigInt(ctx, op2)) {
13447 ret = JS_ToInt32(ctx, &e, op2);13623 ret = JS_ToBigInt64(ctx, &e, op2);
13448#else13624 } else {
13449 ret = JS_ToInt64(ctx, &e, op2);13625 ret = JS_ToInt64(ctx, &e, op2);
13450#endif13626 }
13451 if (ret) {13627 if (ret) {
13452 if (a == &a_s)13628 if (a == &a_s)
13453 bf_delete(a);13629 bf_delete(a);
13630 JS_FreeValue(ctx, res);
13454 return -1;13631 return -1;
13455 }13632 }
13456 13633
13457 bf_init(ctx->bf_ctx, r);
13458 bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);13634 bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
13459 if (a == &a_s)13635 if (a == &a_s)
13460 bf_delete(a);13636 bf_delete(a);
13461 JS_FreeValue(ctx, op1);13637 JS_FreeValue(ctx, op1);
13462 JS_FreeValue(ctx, op2);13638 JS_FreeValue(ctx, op2);
13463 sp[-2] = JS_NewBigFloat(ctx, r);13639 sp[-2] = res;
13464 return 0;13640 return 0;
13465}13641}
13466 13642
@@ -13882,22 +14058,9 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 415 unmodified lines
13882 d2 = JS_VALUE_GET_INT(op2);14058 d2 = JS_VALUE_GET_INT(op2);
13883 goto number_test;14059 goto number_test;
13884 } else if (tag2 == JS_TAG_FLOAT64) {14060 } else if (tag2 == JS_TAG_FLOAT64) {
13885#ifdef CONFIG_BIGNUM14061 d2 = JS_VALUE_GET_FLOAT64(op2);
13886 if (is_bigint_mode(ctx)) {14062 goto number_test;
13887 res = FALSE;14063 } else {
13888 } else
13889#endif
13890 {
13891 d2 = JS_VALUE_GET_FLOAT64(op2);
13892 goto number_test;
13893 }
13894 } else
13895#ifdef CONFIG_BIGNUM
13896 if (tag2 == JS_TAG_BIG_INT && is_bigint_mode(ctx)) {
13897 goto bigint_test;
13898 } else
13899#endif
13900 {
13901 res = FALSE;14064 res = FALSE;
13902 }14065 }
13903 break;14066 break;
@@ -13905,11 +14068,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 1 unmodified line
13905 d1 = JS_VALUE_GET_FLOAT64(op1);14068 d1 = JS_VALUE_GET_FLOAT64(op1);
13906 if (tag2 == JS_TAG_FLOAT64) {14069 if (tag2 == JS_TAG_FLOAT64) {
13907 d2 = JS_VALUE_GET_FLOAT64(op2);14070 d2 = JS_VALUE_GET_FLOAT64(op2);
13908 } else if (tag2 == JS_TAG_INT14071 } else if (tag2 == JS_TAG_INT) {
13909#ifdef CONFIG_BIGNUM
13910 && !is_bigint_mode(ctx)
13911#endif
13912 ) {
13913 d2 = JS_VALUE_GET_INT(op2);14072 d2 = JS_VALUE_GET_INT(op2);
13914 } else {14073 } else {
13915 res = FALSE;14074 res = FALSE;
@@ -13936,15 +14095,10 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 20 unmodified lines
13936 case JS_TAG_BIG_INT:14095 case JS_TAG_BIG_INT:
13937 {14096 {
13938 bf_t a_s, *a, b_s, *b;14097 bf_t a_s, *a, b_s, *b;
13939 if (tag1 == tag2) {14098 if (tag1 != tag2) {
13940 /* OK */
13941 } else if (tag2 == JS_TAG_INT && is_bigint_mode(ctx)) {
13942 /* OK */
13943 } else {
13944 res = FALSE;14099 res = FALSE;
13945 break;14100 break;
13946 }14101 }
13947 bigint_test:
13948 a = JS_ToBigFloat(ctx, &a_s, op1);14102 a = JS_ToBigFloat(ctx, &a_s, op1);
13949 b = JS_ToBigFloat(ctx, &b_s, op2);14103 b = JS_ToBigFloat(ctx, &b_s, op2);
13950 res = bf_cmp_eq(a, b);14104 res = bf_cmp_eq(a, b);
@@ -14100,30 +14254,20 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) · 149 unmodified lines
14100 tag = JS_VALUE_GET_NORM_TAG(op1);14254 tag = JS_VALUE_GET_NORM_TAG(op1);
14101 switch(tag) {14255 switch(tag) {
14102#ifdef CONFIG_BIGNUM14256#ifdef CONFIG_BIGNUM
14103 case JS_TAG_INT:
14104 if (is_bigint_mode(ctx))
14105 atom = JS_ATOM_bigint;
14106 else
14107 atom = JS_ATOM_number;
14108 break;
14109 case JS_TAG_BIG_INT:14257 case JS_TAG_BIG_INT:
14110 atom = JS_ATOM_bigint;14258 atom = JS_ATOM_bigint;
14111 break;14259 break;
14112 case JS_TAG_FLOAT64:
14113 atom = JS_ATOM_number;
14114 break;
14115 case JS_TAG_BIG_FLOAT:14260 case JS_TAG_BIG_FLOAT:
14116 atom = JS_ATOM_bigfloat;14261 atom = JS_ATOM_bigfloat;
14117 break;14262 break;
14118 case JS_TAG_BIG_DECIMAL:14263 case JS_TAG_BIG_DECIMAL:
14119 atom = JS_ATOM_bigdecimal;14264 atom = JS_ATOM_bigdecimal;
14120 break;14265 break;
14121#else14266#endif
14122 case JS_TAG_INT:14267 case JS_TAG_INT:
14123 case JS_TAG_FLOAT64:14268 case JS_TAG_FLOAT64:
14124 atom = JS_ATOM_number;14269 atom = JS_ATOM_number;
14125 break;14270 break;
14126#endif
14127 case JS_TAG_UNDEFINED:14271 case JS_TAG_UNDEFINED:
14128 atom = JS_ATOM_undefined;14272 atom = JS_ATOM_undefined;
14129 break;14273 break;
@@ -15288,7 +15432,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, · 1158 unmodified lines
15288 /* we only propagate the bignum mode as some runtime functions15432 /* we only propagate the bignum mode as some runtime functions
15289 test it */15433 test it */
15290 if (prev_sf)15434 if (prev_sf)
15291 sf->js_mode = prev_sf->js_mode & JS_MODE_BIGINT;15435 sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
15292 else15436 else
15293 sf->js_mode = 0;15437 sf->js_mode = 0;
15294#else15438#else
@@ -17315,11 +17459,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 2020 unmodified lines
17315 v1 = JS_VALUE_GET_INT(op1);17459 v1 = JS_VALUE_GET_INT(op1);
17316 v2 = JS_VALUE_GET_INT(op2);17460 v2 = JS_VALUE_GET_INT(op2);
17317 r = (int64_t)v1 * v2;17461 r = (int64_t)v1 * v2;
17318#ifdef CONFIG_BIGNUM
17319 if (unlikely((int)r != r) || (r == 0 && !is_bigint_mode(ctx)))
17320 goto binary_arith_slow;
17321#else
17322 if (unlikely((int)r != r)) {17462 if (unlikely((int)r != r)) {
17463#ifdef CONFIG_BIGNUM
17464 if (unlikely(sf->js_mode & JS_MODE_MATH) &&
17465 (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
17466 goto binary_arith_slow;
17467#endif
17323 d = (double)r;17468 d = (double)r;
17324 goto mul_fp_res;17469 goto mul_fp_res;
17325 }17470 }
@@ -17328,14 +17473,15 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 2 unmodified lines
17328 d = -0.0;17473 d = -0.0;
17329 goto mul_fp_res;17474 goto mul_fp_res;
17330 }17475 }
17331#endif
17332 sp[-2] = JS_NewInt32(ctx, r);17476 sp[-2] = JS_NewInt32(ctx, r);
17333 sp--;17477 sp--;
17334 } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {17478 } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17479#ifdef CONFIG_BIGNUM
17480 if (unlikely(sf->js_mode & JS_MODE_MATH))
17481 goto binary_arith_slow;
17482#endif
17335 d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);17483 d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
17336#ifndef CONFIG_BIGNUM
17337 mul_fp_res:17484 mul_fp_res:
17338#endif
17339 sp[-2] = __JS_NewFloat64(ctx, d);17485 sp[-2] = __JS_NewFloat64(ctx, d);
17340 sp--;17486 sp--;
17341 } else {17487 } else {
@@ -17343,11 +17489,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 1 unmodified line
17343 }17489 }
17344 }17490 }
17345 BREAK;17491 BREAK;
17346#ifdef CONFIG_BIGNUM
17347 CASE(OP_math_div):
17348 CASE(OP_div):
17349 goto binary_arith_slow;
17350#else
17351 CASE(OP_div):17492 CASE(OP_div):
17352 {17493 {
17353 JSValue op1, op2;17494 JSValue op1, op2;
@@ -17355,6 +17496,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 1 unmodified line
17355 op2 = sp[-1];17496 op2 = sp[-1];
17356 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {17497 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
17357 int v1, v2;17498 int v1, v2;
17499 if (unlikely(sf->js_mode & JS_MODE_MATH))
17500 goto binary_arith_slow;
17358 v1 = JS_VALUE_GET_INT(op1);17501 v1 = JS_VALUE_GET_INT(op1);
17359 v2 = JS_VALUE_GET_INT(op2);17502 v2 = JS_VALUE_GET_INT(op2);
17360 sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);17503 sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
@@ -17364,7 +17507,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 3 unmodified lines
17364 }17507 }
17365 }17508 }
17366 BREAK;17509 BREAK;
17367#endif
17368 CASE(OP_mod):17510 CASE(OP_mod):
17369#ifdef CONFIG_BIGNUM17511#ifdef CONFIG_BIGNUM
17370 CASE(OP_math_mod):17512 CASE(OP_math_mod):
@@ -17390,9 +17532,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 19 unmodified lines
17390 }17532 }
17391 BREAK;17533 BREAK;
17392 CASE(OP_pow):17534 CASE(OP_pow):
17393#ifdef CONFIG_BIGNUM
17394 CASE(OP_math_pow):
17395#endif
17396 binary_arith_slow:17535 binary_arith_slow:
17397 if (js_binary_arith_slow(ctx, sp, opcode))17536 if (js_binary_arith_slow(ctx, sp, opcode))
17398 goto exception;17537 goto exception;
@@ -17422,11 +17561,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 23 unmodified lines
17422 tag = JS_VALUE_GET_TAG(op1);17561 tag = JS_VALUE_GET_TAG(op1);
17423 if (tag == JS_TAG_INT) {17562 if (tag == JS_TAG_INT) {
17424 val = JS_VALUE_GET_INT(op1);17563 val = JS_VALUE_GET_INT(op1);
17425#ifdef CONFIG_BIGNUM
17426 if (unlikely(val == INT32_MIN) ||
17427 (val == 0 && !is_bigint_mode(ctx)))
17428 goto slow_neg;
17429#else
17430 /* Note: -0 cannot be expressed as integer */17564 /* Note: -0 cannot be expressed as integer */
17431 if (unlikely(val == 0)) {17565 if (unlikely(val == 0)) {
17432 d = -0.0;17566 d = -0.0;
@@ -17436,18 +17570,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 3 unmodified lines
17436 d = -(double)val;17570 d = -(double)val;
17437 goto neg_fp_res;17571 goto neg_fp_res;
17438 }17572 }
17439#endif
17440 sp[-1] = JS_NewInt32(ctx, -val);17573 sp[-1] = JS_NewInt32(ctx, -val);
17441 } else if (JS_TAG_IS_FLOAT64(tag)) {17574 } else if (JS_TAG_IS_FLOAT64(tag)) {
17442 d = -JS_VALUE_GET_FLOAT64(op1);17575 d = -JS_VALUE_GET_FLOAT64(op1);
17443#ifndef CONFIG_BIGNUM
17444 neg_fp_res:17576 neg_fp_res:
17445#endif
17446 sp[-1] = __JS_NewFloat64(ctx, d);17577 sp[-1] = __JS_NewFloat64(ctx, d);
17447 } else {17578 } else {
17448#ifdef CONFIG_BIGNUM
17449 slow_neg:
17450#endif
17451 if (js_unary_arith_slow(ctx, sp, opcode))17579 if (js_unary_arith_slow(ctx, sp, opcode))
17452 goto exception;17580 goto exception;
17453 }17581 }
@@ -17560,7 +17688,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 106 unmodified lines
17560#ifdef CONFIG_BIGNUM17688#ifdef CONFIG_BIGNUM
17561 {17689 {
17562 int64_t r;17690 int64_t r;
17563 if (is_bigint_mode(ctx)) {17691 if (unlikely(sf->js_mode & JS_MODE_MATH)) {
17564 if (v2 > 0x1f)17692 if (v2 > 0x1f)
17565 goto shl_slow;17693 goto shl_slow;
17566 r = (int64_t)v1 << v2;17694 r = (int64_t)v1 << v2;
@@ -17616,7 +17744,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 49 unmodified lines
17616 v2 = JS_VALUE_GET_INT(op2);17744 v2 = JS_VALUE_GET_INT(op2);
17617#ifdef CONFIG_BIGNUM17745#ifdef CONFIG_BIGNUM
17618 if (unlikely(v2 > 0x1f)) {17746 if (unlikely(v2 > 0x1f)) {
17619 if (is_bigint_mode(ctx))17747 if (unlikely(sf->js_mode & JS_MODE_MATH))
17620 goto sar_slow;17748 goto sar_slow;
17621 else17749 else
17622 v2 &= 0x1f;17750 v2 &= 0x1f;
@@ -20182,7 +20310,7 @@ static __exception int next_token(JSParseState *s) · 2559 unmodified lines
20182 ATOD_ACCEPT_UNDERSCORES;20310 ATOD_ACCEPT_UNDERSCORES;
20183#ifdef CONFIG_BIGNUM20311#ifdef CONFIG_BIGNUM
20184 flags |= ATOD_ACCEPT_SUFFIX;20312 flags |= ATOD_ACCEPT_SUFFIX;
20185 if (s->cur_func->js_mode & JS_MODE_BIGINT) {20313 if (s->cur_func->js_mode & JS_MODE_MATH) {
20186 flags |= ATOD_MODE_BIGINT;20314 flags |= ATOD_MODE_BIGINT;
20187 if (s->cur_func->js_mode & JS_MODE_MATH)20315 if (s->cur_func->js_mode & JS_MODE_MATH)
20188 flags |= ATOD_TYPE_BIG_FLOAT;20316 flags |= ATOD_TYPE_BIG_FLOAT;
@@ -23312,7 +23440,6 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 3123 unmodified lines
23312 } else23440 } else
23313#ifdef CONFIG_BIGNUM23441#ifdef CONFIG_BIGNUM
23314 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {23442 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
23315 bf_t r_s, *r = &r_s;
23316 slimb_t e;23443 slimb_t e;
23317 int ret;23444 int ret;
23318 23445
@@ -23326,9 +23453,9 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 7 unmodified lines
23326 emit_op(s, OP_push_i32);23453 emit_op(s, OP_push_i32);
23327 emit_u32(s, e);23454 emit_u32(s, e);
23328 } else {23455 } else {
23329 bf_init(s->ctx->bf_ctx, r);23456 val = JS_NewBigInt64_1(s->ctx, e);
23330 bf_set_si(r, e);23457 if (JS_IsException(val))
23331 val = JS_NewBigInt(s->ctx, r);23458 return -1;
23332 ret = emit_push_const(s, val, 0);23459 ret = emit_push_const(s, val, 0);
23333 JS_FreeValue(s->ctx, val);23460 JS_FreeValue(s->ctx, val);
23334 if (ret < 0)23461 if (ret < 0)
@@ -24105,10 +24232,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) · 770 unmodified lines
24105 return -1;24232 return -1;
24106 if (js_parse_unary(s, 1))24233 if (js_parse_unary(s, 1))
24107 return -1;24234 return -1;
24108 if (s->cur_func->js_mode & JS_MODE_MATH)24235 emit_op(s, OP_pow);
24109 emit_op(s, OP_math_pow);
24110 else
24111 emit_op(s, OP_pow);
24112 }24236 }
24113#else24237#else
24114 if (s->token.val == TOK_POW) {24238 if (s->token.val == TOK_POW) {
@@ -24151,12 +24275,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, · 36 unmodified lines
24151 opcode = OP_mul;24275 opcode = OP_mul;
24152 break;24276 break;
24153 case '/':24277 case '/':
24154#ifdef CONFIG_BIGNUM24278 opcode = OP_div;
24155 if (s->cur_func->js_mode & JS_MODE_MATH)
24156 opcode = OP_math_div;
24157 else
24158#endif
24159 opcode = OP_div;
24160 break;24279 break;
24161 case '%':24280 case '%':
24162#ifdef CONFIG_BIGNUM24281#ifdef CONFIG_BIGNUM
@@ -24549,12 +24668,8 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) · 386 unmodified lines
24549 op = assign_opcodes[op - TOK_MUL_ASSIGN];24668 op = assign_opcodes[op - TOK_MUL_ASSIGN];
24550#ifdef CONFIG_BIGNUM24669#ifdef CONFIG_BIGNUM
24551 if (s->cur_func->js_mode & JS_MODE_MATH) {24670 if (s->cur_func->js_mode & JS_MODE_MATH) {
24552 if (op == OP_div)24671 if (op == OP_mod)
24553 op = OP_math_div;
24554 else if (op == OP_mod)
24555 op = OP_math_mod;24672 op = OP_math_mod;
24556 else if (op == OP_pow)
24557 op = OP_math_pow;
24558 }24673 }
24559#endif24674#endif
24560 emit_op(s, op);24675 emit_op(s, op);
@@ -30149,20 +30264,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) · 5588 unmodified lines
30149 len = opcode_info[op].size;30264 len = opcode_info[op].size;
30150 pos_next = pos + len;30265 pos_next = pos + len;
30151 switch(op) {30266 switch(op) {
30152 case OP_close_var_object:
30153 {
30154 if (s->var_object_idx >= 0) {
30155 /* close the var object and create a new one */
30156 add_pc2line_info(s, bc_out.size, line_num);
30157 dbuf_putc(&bc_out, OP_close_loc);
30158 dbuf_put_u16(&bc_out, s->var_object_idx);
30159 dbuf_putc(&bc_out, OP_special_object);
30160 dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
30161 put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
30162 }
30163 }
30164 break;
30165
30166 case OP_line_num:30267 case OP_line_num:
30167 /* line number info (for debug). We put it in a separate30268 /* line number info (for debug). We put it in a separate
30168 compressed table to reduce memory usage and get better30269 compressed table to reduce memory usage and get better
@@ -31508,11 +31609,8 @@ static __exception int js_parse_directives(JSParseState *s) · 1339 unmodified lines
31508 }31609 }
31509#endif31610#endif
31510#ifdef CONFIG_BIGNUM31611#ifdef CONFIG_BIGNUM
31511 else if (s->ctx->bignum_ext && !strcmp(str, "use bigint")) {
31512 s->cur_func->js_mode |= JS_MODE_BIGINT;
31513 }
31514 else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {31612 else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
31515 s->cur_func->js_mode |= JS_MODE_BIGINT | JS_MODE_MATH;31613 s->cur_func->js_mode |= JS_MODE_MATH;
31516 }31614 }
31517#endif31615#endif
31518 }31616 }
@@ -31804,13 +31902,6 @@ static __exception int js_parse_function_decl2(JSParseState *s, · 285 unmodified lines
31804 }31902 }
31805 if (js_parse_destructing_element(s, TOK_VAR, 1, TRUE, -1, TRUE))31903 if (js_parse_destructing_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
31806 goto fail;31904 goto fail;
31807 /* Close var object: necessary if direct eval call
31808 occurred in the assignment expression or if any
31809 variable was captured and a later direct eval call
31810 may instantiate it in the var object.
31811 The next pass will generate the capture if required.
31812 */
31813 emit_op(s, OP_close_var_object);
31814 } else if (s->token.val == TOK_IDENT) {31905 } else if (s->token.val == TOK_IDENT) {
31815 if (s->token.u.ident.is_reserved) {31906 if (s->token.u.ident.is_reserved) {
31816 js_parse_error_reserved_identifier(s);31907 js_parse_error_reserved_identifier(s);
@@ -31889,8 +31980,6 @@ static __exception int js_parse_function_decl2(JSParseState *s, · 72 unmodified lines
31889 set_object_name(s, name);31980 set_object_name(s, name);
31890 emit_op(s, OP_put_arg);31981 emit_op(s, OP_put_arg);
31891 emit_u16(s, idx);31982 emit_u16(s, idx);
31892 /* Close var object: see above comment. */
31893 emit_op(s, OP_close_var_object);
31894 emit_label(s, label);31983 emit_label(s, label);
31895 }31984 }
31896 } else if (!has_opt_arg) {31985 } else if (!has_opt_arg) {
@@ -34399,30 +34488,20 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) · 2502 unmodified lines
34399 case JS_TAG_EXCEPTION:34488 case JS_TAG_EXCEPTION:
34400 return JS_DupValue(ctx, val);34489 return JS_DupValue(ctx, val);
34401#ifdef CONFIG_BIGNUM34490#ifdef CONFIG_BIGNUM
34402 case JS_TAG_INT:
34403 if (is_bigint_mode(ctx))
34404 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
34405 else
34406 obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
34407 goto set_value;
34408 case JS_TAG_BIG_INT:34491 case JS_TAG_BIG_INT:
34409 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);34492 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
34410 goto set_value;34493 goto set_value;
34411 case JS_TAG_FLOAT64:
34412 obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
34413 goto set_value;
34414 case JS_TAG_BIG_FLOAT:34494 case JS_TAG_BIG_FLOAT:
34415 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);34495 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
34416 goto set_value;34496 goto set_value;
34417 case JS_TAG_BIG_DECIMAL:34497 case JS_TAG_BIG_DECIMAL:
34418 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);34498 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
34419 goto set_value;34499 goto set_value;
34420#else34500#endif
34421 case JS_TAG_INT:34501 case JS_TAG_INT:
34422 case JS_TAG_FLOAT64:34502 case JS_TAG_FLOAT64:
34423 obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);34503 obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
34424 goto set_value;34504 goto set_value;
34425#endif
34426 case JS_TAG_STRING:34505 case JS_TAG_STRING:
34427 /* XXX: should call the string constructor */34506 /* XXX: should call the string constructor */
34428 {34507 {
@@ -34995,10 +35074,13 @@ static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val · 566 unmodified lines
34995 ret = JS_PreventExtensions(ctx, obj);35074 ret = JS_PreventExtensions(ctx, obj);
34996 if (ret < 0)35075 if (ret < 0)
34997 return JS_EXCEPTION;35076 return JS_EXCEPTION;
34998 if (reflect)35077 if (reflect) {
34999 return JS_NewBool(ctx, ret);35078 return JS_NewBool(ctx, ret);
35000 else35079 } else {
35080 if (!ret)
35081 return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
35001 return JS_DupValue(ctx, obj);35082 return JS_DupValue(ctx, obj);
35083 }
35002}35084}
35003 35085
35004static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,35086static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
@@ -35166,7 +35248,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, · 161 unmodified lines
35166 goto exception;35248 goto exception;
35167 }35249 }
35168 js_free_prop_enum(ctx, props, len);35250 js_free_prop_enum(ctx, props, len);
35169 return JS_TRUE;35251 return JS_DupValue(ctx, obj);
35170 35252
35171 exception:35253 exception:
35172 js_free_prop_enum(ctx, props, len);35254 js_free_prop_enum(ctx, props, len);
@@ -37690,17 +37772,14 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, · 2517 unmodified lines
37690 int argc, JSValueConst *argv)37772 int argc, JSValueConst *argv)
37691{37773{
37692 JSValue val, obj;37774 JSValue val, obj;
37693#ifdef CONFIG_BIGNUM
37694 if (argc == 0) {37775 if (argc == 0) {
37695 if (is_bigint_mode(ctx))37776 val = JS_NewInt32(ctx, 0);
37696 val = __JS_NewFloat64(ctx, 0);
37697 else
37698 val = JS_NewInt32(ctx, 0);
37699 } else {37777 } else {
37700 val = JS_ToNumeric(ctx, argv[0]);37778 val = JS_ToNumeric(ctx, argv[0]);
37701 if (JS_IsException(val))37779 if (JS_IsException(val))
37702 return val;37780 return val;
37703 switch(JS_VALUE_GET_TAG(val)) {37781 switch(JS_VALUE_GET_TAG(val)) {
37782#ifdef CONFIG_BIGNUM
37704 case JS_TAG_BIG_INT:37783 case JS_TAG_BIG_INT:
37705 case JS_TAG_BIG_FLOAT:37784 case JS_TAG_BIG_FLOAT:
37706 {37785 {
@@ -37711,25 +37790,19 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, · 4 unmodified lines
37711 val = __JS_NewFloat64(ctx, d);37790 val = __JS_NewFloat64(ctx, d);
37712 }37791 }
37713 break;37792 break;
37714 case JS_TAG_INT:37793 case JS_TAG_BIG_DECIMAL:
37715 if (is_bigint_mode(ctx)) {37794 val = JS_ToStringFree(ctx, val);
37716 /* always return a number in bignum mode */37795 if (JS_IsException(val))
37717 val = __JS_NewFloat64(ctx, JS_VALUE_GET_INT(val));37796 return val;
37718 }37797 val = JS_ToNumberFree(ctx, val);
37798 if (JS_IsException(val))
37799 return val;
37719 break;37800 break;
37801#endif
37720 default:37802 default:
37721 break;37803 break;
37722 }37804 }
37723 }37805 }
37724#else
37725 if (argc == 0) {
37726 val = JS_NewInt32(ctx, 0);
37727 } else {
37728 val = JS_ToNumber(ctx, argv[0]);
37729 if (JS_IsException(val))
37730 return val;
37731 }
37732#endif
37733 if (!JS_IsUndefined(new_target)) {37806 if (!JS_IsUndefined(new_target)) {
37734 obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);37807 obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
37735 if (!JS_IsException(obj))37808 if (!JS_IsException(obj))
@@ -37760,7 +37833,6 @@ static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val, · 24 unmodified lines
37760static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,37833static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
37761 int argc, JSValueConst *argv)37834 int argc, JSValueConst *argv)
37762{37835{
37763 /* XXX: should just check for float and big_float */
37764 if (!JS_IsNumber(argv[0]))37836 if (!JS_IsNumber(argv[0]))
37765 return JS_FALSE;37837 return JS_FALSE;
37766 return js_global_isNaN(ctx, this_val, argc, argv);37838 return js_global_isNaN(ctx, this_val, argc, argv);
@@ -37793,8 +37865,7 @@ static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val, · 26 unmodified lines
37793 return JS_FALSE;37865 return JS_FALSE;
37794 if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))37866 if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
37795 return JS_EXCEPTION;37867 return JS_EXCEPTION;
37796 return JS_NewBool(ctx, isfinite(d) && floor(d) == d &&37868 return JS_NewBool(ctx, is_safe_integer(d));
37797 fabs(d) <= (double)MAX_SAFE_INTEGER);
37798}37869}
37799 37870
37800static const JSCFunctionListEntry js_number_funcs[] = {37871static const JSCFunctionListEntry js_number_funcs[] = {
@@ -37838,6 +37909,18 @@ static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val, · 37 unmodified lines
37838 return js_thisNumberValue(ctx, this_val);37909 return js_thisNumberValue(ctx, this_val);
37839}37910}
37840 37911
37912static int js_get_radix(JSContext *ctx, JSValueConst val)
37913{
37914 int radix;
37915 if (JS_ToInt32Sat(ctx, &radix, val))
37916 return -1;
37917 if (radix < 2 || radix > 36) {
37918 JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
37919 return -1;
37920 }
37921 return radix;
37922}
37923
37841static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,37924static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
37842 int argc, JSValueConst *argv, int magic)37925 int argc, JSValueConst *argv, int magic)
37843{37926{
@@ -37851,12 +37934,9 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val, · 7 unmodified lines
37851 if (magic || JS_IsUndefined(argv[0])) {37934 if (magic || JS_IsUndefined(argv[0])) {
37852 base = 10;37935 base = 10;
37853 } else {37936 } else {
37854 if (JS_ToInt32Sat(ctx, &base, argv[0]))37937 base = js_get_radix(ctx, argv[0]);
37855 goto fail;37938 if (base < 0)
37856 if (base < 2 || base > 36) {
37857 JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
37858 goto fail;37939 goto fail;
37859 }
37860 }37940 }
37861 if (JS_ToFloat64Free(ctx, &d, val))37941 if (JS_ToFloat64Free(ctx, &d, val))
37862 return JS_EXCEPTION;37942 return JS_EXCEPTION;
@@ -37972,10 +38052,6 @@ static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val, · 109 unmodified lines
37972 p = str;38052 p = str;
37973 p += skip_spaces(p);38053 p += skip_spaces(p);
37974 flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;38054 flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
37975#ifdef CONFIG_BIGNUM
37976 if (is_bigint_mode(ctx))
37977 flags |= ATOD_MODE_BIGINT;
37978#endif
37979 ret = js_atof(ctx, p, NULL, radix, flags);38055 ret = js_atof(ctx, p, NULL, radix, flags);
37980 }38056 }
37981 JS_FreeCString(ctx, str);38057 JS_FreeCString(ctx, str);
@@ -39738,348 +39814,6 @@ static double js_fmax(double a, double b) · 1756 unmodified lines
39738 }39814 }
39739}39815}
39740 39816
39741#ifdef CONFIG_BIGNUM
39742
39743enum {
39744 MATH_OP_ABS,
39745 MATH_OP_FLOOR,
39746 MATH_OP_CEIL,
39747 MATH_OP_ROUND,
39748 MATH_OP_TRUNC,
39749 MATH_OP_SQRT,
39750 MATH_OP_FPROUND,
39751 MATH_OP_ACOS,
39752 MATH_OP_ASIN,
39753 MATH_OP_ATAN,
39754 MATH_OP_ATAN2,
39755 MATH_OP_COS,
39756 MATH_OP_EXP,
39757 MATH_OP_LOG,
39758 MATH_OP_POW,
39759 MATH_OP_SIN,
39760 MATH_OP_TAN,
39761 MATH_OP_FMOD,
39762 MATH_OP_REM,
39763 MATH_OP_SIGN,
39764
39765 MATH_OP_ADD,
39766 MATH_OP_SUB,
39767 MATH_OP_MUL,
39768 MATH_OP_DIV,
39769};
39770
39771static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
39772 int argc, JSValueConst *argv, int magic)
39773{
39774 bf_t a_s, *a, r_s, *r = &r_s;
39775 JSFloatEnv *fe;
39776 int rnd_mode;
39777 JSValue op1;
39778
39779 op1 = JS_ToNumber(ctx, argv[0]);
39780 if (JS_IsException(op1))
39781 return op1;
39782 a = JS_ToBigFloat(ctx, &a_s, op1);
39783 fe = &ctx->fp_env;
39784 if (argc > 1) {
39785 fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
39786 if (!fe) {
39787 if (a == &a_s)
39788 bf_delete(a);
39789 JS_FreeValue(ctx, op1);
39790 return JS_EXCEPTION;
39791 }
39792 }
39793
39794 bf_init(ctx->bf_ctx, r);
39795 switch (magic) {
39796 case MATH_OP_ABS:
39797 bf_set(r, a);
39798 r->sign = 0;
39799 break;
39800 case MATH_OP_FLOOR:
39801 rnd_mode = BF_RNDD;
39802 goto rint;
39803 case MATH_OP_CEIL:
39804 rnd_mode = BF_RNDU;
39805 goto rint;
39806 case MATH_OP_ROUND:
39807 rnd_mode = BF_RNDNU;
39808 goto rint;
39809 case MATH_OP_TRUNC:
39810 rnd_mode = BF_RNDZ;
39811 rint:
39812 bf_set(r, a);
39813 fe->status |= bf_rint(r, rnd_mode);
39814 break;
39815 case MATH_OP_SQRT:
39816 fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
39817 break;
39818 case MATH_OP_FPROUND:
39819 bf_set(r, a);
39820 fe->status |= bf_round(r, fe->prec, fe->flags);
39821 break;
39822 case MATH_OP_ACOS:
39823 fe->status |= bf_acos(r, a, fe->prec, fe->flags);
39824 break;
39825 case MATH_OP_ASIN:
39826 fe->status |= bf_asin(r, a, fe->prec, fe->flags);
39827 break;
39828 case MATH_OP_ATAN:
39829 fe->status |= bf_atan(r, a, fe->prec, fe->flags);
39830 break;
39831 case MATH_OP_COS:
39832 fe->status |= bf_cos(r, a, fe->prec, fe->flags);
39833 break;
39834 case MATH_OP_EXP:
39835 fe->status |= bf_exp(r, a, fe->prec, fe->flags);
39836 break;
39837 case MATH_OP_LOG:
39838 fe->status |= bf_log(r, a, fe->prec, fe->flags);
39839 break;
39840 case MATH_OP_SIN:
39841 fe->status |= bf_sin(r, a, fe->prec, fe->flags);
39842 break;
39843 case MATH_OP_TAN:
39844 fe->status |= bf_tan(r, a, fe->prec, fe->flags);
39845 break;
39846 case MATH_OP_SIGN:
39847 if (bf_is_nan(a) || bf_is_zero(a)) {
39848 bf_set(r, a);
39849 } else {
39850 bf_set_si(r, 1 - 2 * a->sign);
39851 }
39852 break;
39853 default:
39854 abort();
39855 }
39856 if (a == &a_s)
39857 bf_delete(a);
39858 JS_FreeValue(ctx, op1);
39859 return JS_NewBigFloat(ctx, r);
39860}
39861
39862static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
39863 int argc, JSValueConst *argv, int magic)
39864{
39865 bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
39866 JSFloatEnv *fe;
39867 JSValue op1, op2;
39868
39869 op1 = JS_ToNumber(ctx, argv[0]);
39870 if (JS_IsException(op1))
39871 return op1;
39872 op2 = JS_ToNumber(ctx, argv[1]);
39873 if (JS_IsException(op2)) {
39874 JS_FreeValue(ctx, op1);
39875 return op2;
39876 }
39877 a = JS_ToBigFloat(ctx, &a_s, op1);
39878 b = JS_ToBigFloat(ctx, &b_s, op2);
39879 fe = &ctx->fp_env;
39880 if (argc > 2) {
39881 fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
39882 if (!fe) {
39883 if (a == &a_s)
39884 bf_delete(a);
39885 if (b == &b_s)
39886 bf_delete(b);
39887 JS_FreeValue(ctx, op1);
39888 JS_FreeValue(ctx, op2);
39889 return JS_EXCEPTION;
39890 }
39891 }
39892
39893 bf_init(ctx->bf_ctx, r);
39894 switch (magic) {
39895 case MATH_OP_ATAN2:
39896 fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
39897 break;
39898 case MATH_OP_POW:
39899 fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUICKS);
39900 break;
39901 case MATH_OP_FMOD:
39902 fe->status |= bf_fmod(r, a, b, fe->prec, fe->flags);
39903 break;
39904 case MATH_OP_REM:
39905 fe->status |= bf_remainder(r, a, b, fe->prec, fe->flags);
39906 break;
39907 case MATH_OP_ADD:
39908 fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
39909 break;
39910 case MATH_OP_SUB:
39911 fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
39912 break;
39913 case MATH_OP_MUL:
39914 fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
39915 break;
39916 case MATH_OP_DIV:
39917 fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
39918 break;
39919 default:
39920 abort();
39921 }
39922 if (a == &a_s)
39923 bf_delete(a);
39924 if (b == &b_s)
39925 bf_delete(b);
39926 JS_FreeValue(ctx, op1);
39927 JS_FreeValue(ctx, op2);
39928 return JS_NewBigFloat(ctx, r);
39929}
39930
39931static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
39932 int argc, JSValueConst *argv, int magic)
39933{
39934 BOOL is_max = magic;
39935 JSValue val, ret;
39936 int i;
39937 uint32_t tag;
39938
39939 if (unlikely(argc == 0)) {
39940 return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
39941 }
39942
39943 tag = JS_VALUE_GET_TAG(argv[0]);
39944 if (tag == JS_TAG_INT) {
39945 int a1, r1 = JS_VALUE_GET_INT(argv[0]);
39946 for(i = 1; i < argc; i++) {
39947 tag = JS_VALUE_GET_TAG(argv[i]);
39948 if (tag != JS_TAG_INT) {
39949 ret = JS_NewInt32(ctx, r1);
39950 goto generic_case;
39951 }
39952 a1 = JS_VALUE_GET_INT(argv[i]);
39953 if (is_max)
39954 r1 = max_int(r1, a1);
39955 else
39956 r1 = min_int(r1, a1);
39957 }
39958 ret = JS_NewInt32(ctx, r1);
39959 } else {
39960 ret = JS_ToNumber(ctx, argv[0]);
39961 if (JS_IsException(ret))
39962 return ret;
39963 i = 1;
39964 generic_case:
39965 for(; i < argc; i++) {
39966 val = JS_ToNumber(ctx, argv[i]);
39967 if (JS_IsException(val)) {
39968 JS_FreeValue(ctx, ret);
39969 return val;
39970 }
39971 if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(ret)) &&
39972 JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(val))) {
39973 double r, a;
39974 r = JS_VALUE_GET_FLOAT64(ret);
39975 a = JS_VALUE_GET_FLOAT64(val);
39976 if (!isnan(r)) {
39977 if (isnan(a)) {
39978 r = a;
39979 } else {
39980 if (is_max)
39981 r = js_fmax(r, a);
39982 else
39983 r = js_fmin(r, a);
39984 }
39985 ret = __JS_NewFloat64(ctx, r);
39986 }
39987 } else {
39988 bf_t a_s, *a, r_s, *r;
39989 int res;
39990
39991 r = JS_ToBigFloat(ctx, &r_s, ret);
39992 if (!bf_is_nan(r)) {
39993 a = JS_ToBigFloat(ctx, &a_s, val);
39994 res = bf_cmp_full(a, r);
39995 if (is_max)
39996 res = -res;
39997 if (bf_is_nan(a) || res < 0) {
39998 JS_FreeValue(ctx, ret);
39999 ret = JS_DupValue(ctx, val);
40000 }
40001 if (a == &a_s)
40002 bf_delete(a);
40003 }
40004 if (r == &r_s)
40005 bf_delete(r);
40006 JS_FreeValue(ctx, val);
40007 }
40008 }
40009 }
40010 return ret;
40011}
40012
40013static JSValue js_math_abs(JSContext *ctx, JSValueConst this_val,
40014 int argc, JSValueConst *argv)
40015{
40016 JSValue val;
40017 uint32_t tag;
40018
40019 val = JS_ToNumeric(ctx, argv[0]);
40020 tag = JS_VALUE_GET_NORM_TAG(val);
40021 switch(tag) {
40022 case JS_TAG_INT:
40023 if (JS_VALUE_GET_INT(val) < 0)
40024 val = JS_NewInt64(ctx, -(int64_t)JS_VALUE_GET_INT(val));
40025 break;
40026 case JS_TAG_FLOAT64:
40027 val = __JS_NewFloat64(ctx, fabs(JS_VALUE_GET_FLOAT64(val)));
40028 break;
40029 case JS_TAG_BIG_FLOAT:
40030 case JS_TAG_BIG_INT:
40031 {
40032 JSBigFloat *p = JS_VALUE_GET_PTR(val);
40033 bf_t r_s, *r = &r_s;
40034 bf_init(ctx->bf_ctx, r);
40035 bf_set(r, &p->num);
40036 r->sign = 0;
40037 JS_FreeValue(ctx, val);
40038 if (tag == JS_TAG_BIG_FLOAT)
40039 val = JS_NewBigFloat(ctx, r);
40040 else
40041 val = JS_NewBigInt2(ctx, r, TRUE);
40042 }
40043 break;
40044 default:
40045 break;
40046 }
40047 return val;
40048}
40049
40050#if 0
40051/* XXX: should give exact rounding */
40052/* XXX: correct NaN/Infinity handling */
40053static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
40054 int argc, JSValueConst *argv)
40055{
40056 bf_t a_s, *a, r_s, *r = &r_s, r2_s, *r2 = &r2_s;
40057 JSValue val;
40058 int i;
40059 BOOL is_float;
40060
40061 bf_init(ctx->bf_ctx, r);
40062 bf_set_si(r, 0);
40063 for(i = 0; i < argc; i++) {
40064 val = JS_ToNumber(ctx, argv[i]);
40065 if (JS_IsException(val)) {
40066 bf_delete(r);
40067 return val;
40068 }
40069 a = JS_ToBigFloat(ctx, &is_float, &a_s, val);
40070 bf_add(r, r, a, ctx->fp_env.prec, ctx->fp_env.flags);
40071 if (a == &a_s)
40072 bf_delete(a);
40073 }
40074 bf_init(ctx->bf_ctx, r2);
40075 bf_sqrt(r2, r, ctx->fp_env.prec, ctx->fp_env.flags);
40076 bf_delete(r);
40077 return JS_NewBigFloat(ctx, r2);
40078}
40079#endif
40080
40081#else
40082
40083static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,39817static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
40084 int argc, JSValueConst *argv, int magic)39818 int argc, JSValueConst *argv, int magic)
40085{39819{
@@ -40133,8 +39867,6 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, · 47 unmodified lines
40133 }39867 }
40134}39868}
40135 39869
40136#endif /* !CONFIG_BIGNUM */
40137
40138static double js_math_sign(double a)39870static double js_math_sign(double a)
40139{39871{
40140 if (isnan(a) || a == 0.0)39872 if (isnan(a) || a == 0.0)
@@ -40267,11 +39999,7 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, · 126 unmodified lines
40267static const JSCFunctionListEntry js_math_funcs[] = {39999static const JSCFunctionListEntry js_math_funcs[] = {
40268 JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),40000 JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
40269 JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),40001 JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
40270#ifdef CONFIG_BIGNUM
40271 JS_CFUNC_DEF("abs", 1, js_math_abs ),
40272#else
40273 JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),40002 JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
40274#endif
40275 JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),40003 JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
40276 JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),40004 JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
40277 JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),40005 JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
@@ -41959,46 +41687,12 @@ static JSValue json_parse_value(JSParseState *s) · 1681 unmodified lines
41959 }41687 }
41960 is_neg = 1;41688 is_neg = 1;
41961 number:41689 number:
41962#ifdef CONFIG_BIGNUM
41963 val = JS_DupValue(ctx, s->token.u.num.val);
41964 if (is_neg) {
41965 switch(JS_VALUE_GET_NORM_TAG(val)) {
41966 case JS_TAG_BIG_INT:
41967 case JS_TAG_BIG_FLOAT:
41968 {
41969 JSBigFloat *p;
41970 p = JS_VALUE_GET_PTR(val);
41971 bf_neg(&p->num);
41972 }
41973 break;
41974 case JS_TAG_FLOAT64:
41975 {
41976 double d;
41977 d = JS_VALUE_GET_FLOAT64(val);
41978 val = __JS_NewFloat64(ctx, -d);
41979 }
41980 break;
41981 default:
41982 case JS_TAG_INT:
41983 {
41984 int v;
41985 v = JS_VALUE_GET_INT(val);
41986 if (v == 0 && !is_bigint_mode(s->ctx))
41987 val = __JS_NewFloat64(ctx, -0.0);
41988 else
41989 val = JS_NewInt64(ctx, -(int64_t)v);
41990 }
41991 break;
41992 }
41993 }
41994#else
41995 val = s->token.u.num.val;41690 val = s->token.u.num.val;
41996 if (is_neg) {41691 if (is_neg) {
41997 double d;41692 double d;
41998 JS_ToFloat64(ctx, &d, val); /* no exception possible */41693 JS_ToFloat64(ctx, &d, val); /* no exception possible */
41999 val = JS_NewFloat64(ctx, -d);41694 val = JS_NewFloat64(ctx, -d);
42000 }41695 }
42001#endif
42002 if (next_token(s))41696 if (next_token(s))
42003 goto fail;41697 goto fail;
42004 break;41698 break;
@@ -42168,10 +41862,6 @@ static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) { · 163 unmodified lines
42168 return r;41862 return r;
42169}41863}
42170 41864
42171#ifdef CONFIG_BIGNUM
42172static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v);
42173#endif
42174
42175static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,41865static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
42176 JSValueConst holder, JSValue val, JSValueConst key)41866 JSValueConst holder, JSValue val, JSValueConst key)
42177{41867{
@@ -46764,7 +46454,8 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 4586 unmodified lines
46764 double d;46454 double d;
46765 int p, i, c, sgn;46455 int p, i, c, sgn;
46766 JSString *sp;46456 JSString *sp;
46767 46457 BOOL is_local;
46458
46768 rv = JS_NAN;46459 rv = JS_NAN;
46769 46460
46770 s = JS_ToString(ctx, argv[0]);46461 s = JS_ToString(ctx, argv[0]);
@@ -46780,11 +46471,15 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 9 unmodified lines
46780 if (string_get_signed_field(sp, &p, &fields[0]))46471 if (string_get_signed_field(sp, &p, &fields[0]))
46781 goto done;46472 goto done;
46782 46473
46474 is_local = TRUE;
46783 for (i = 1; i < 6; i++) {46475 for (i = 1; i < 6; i++) {
46784 if (string_get_field(sp, &p, &fields[i]))46476 if (string_get_field(sp, &p, &fields[i]))
46785 break;46477 break;
46786 }46478 }
46787 if (i == 6 && p < sp->len && string_get(sp, p) == '.') {46479 if (i <= 3) {
46480 /* no time: UTC by default */
46481 is_local = FALSE;
46482 } else if (i == 6 && p < sp->len && string_get(sp, p) == '.') {
46788 /* parse milliseconds as a fractional part, round to nearest */46483 /* parse milliseconds as a fractional part, round to nearest */
46789 /* XXX: the spec does not indicate which rounding should be used */46484 /* XXX: the spec does not indicate which rounding should be used */
46790 int mul = 1000, ms = 0;46485 int mul = 1000, ms = 0;
@@ -46802,14 +46497,20 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
46802 46497
46803 /* parse the time zone offset if present: [+-]HH:mm */46498 /* parse the time zone offset if present: [+-]HH:mm */
46804 tz = 0;46499 tz = 0;
46805 if (p < sp->len && ((sgn = string_get(sp, p)) == '+' || sgn == '-')) {46500 if (p < sp->len) {
46806 if (string_get_field(sp, &p, &hh))46501 sgn = string_get(sp, p);
46807 goto done;46502 if (sgn == '+' || sgn == '-') {
46808 if (string_get_field(sp, &p, &mm))46503 if (string_get_field(sp, &p, &hh))
46809 goto done;46504 goto done;
46810 tz = hh * 60 + mm;46505 if (string_get_field(sp, &p, &mm))
46811 if (sgn == '-')46506 goto done;
46812 tz = -tz;46507 tz = hh * 60 + mm;
46508 if (sgn == '-')
46509 tz = -tz;
46510 is_local = FALSE;
46511 } else if (sgn == 'Z') {
46512 is_local = FALSE;
46513 }
46813 }46514 }
46814 } else {46515 } else {
46815 /* toString or toUTCString format */46516 /* toString or toUTCString format */
@@ -46844,6 +46545,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 28 unmodified lines
46844 // XXX: parse optional milliseconds?46545 // XXX: parse optional milliseconds?
46845 46546
46846 /* parse the time zone offset if present: [+-]HHmm */46547 /* parse the time zone offset if present: [+-]HHmm */
46548 is_local = FALSE;
46847 tz = 0;46549 tz = 0;
46848 for (tz = 0; p < sp->len; p++) {46550 for (tz = 0; p < sp->len; p++) {
46849 sgn = string_get(sp, p);46551 sgn = string_get(sp, p);
@@ -46860,7 +46562,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
46860 }46562 }
46861 }46563 }
46862 }46564 }
46863 d = set_date_fields(fields, 0) - tz * 60000;46565 d = set_date_fields(fields, is_local) - tz * 60000;
46864 rv = __JS_NewFloat64(ctx, d);46566 rv = __JS_NewFloat64(ctx, d);
46865 46567
46866done:46568done:
@@ -47080,61 +46782,364 @@ void JS_AddIntrinsicEval(JSContext *ctx) · 213 unmodified lines
47080 46782
47081#ifdef CONFIG_BIGNUM46783#ifdef CONFIG_BIGNUM
47082 46784
46785/* Operators */
46786
46787static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
46788{
46789 JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
46790 int i, j;
46791 JSBinaryOperatorDefEntry *ent;
46792
46793 if (opset) {
46794 for(i = 0; i < JS_OVOP_COUNT; i++) {
46795 if (opset->self_ops[i])
46796 JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
46797 }
46798 for(j = 0; j < opset->left.count; j++) {
46799 ent = &opset->left.tab[j];
46800 for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46801 if (ent->ops[i])
46802 JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
46803 }
46804 }
46805 js_free_rt(rt, opset->left.tab);
46806 for(j = 0; j < opset->right.count; j++) {
46807 ent = &opset->right.tab[j];
46808 for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46809 if (ent->ops[i])
46810 JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
46811 }
46812 }
46813 js_free_rt(rt, opset->right.tab);
46814 js_free_rt(rt, opset);
46815 }
46816}
46817
46818static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
46819 JS_MarkFunc *mark_func)
46820{
46821 JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
46822 int i, j;
46823 JSBinaryOperatorDefEntry *ent;
46824
46825 if (opset) {
46826 for(i = 0; i < JS_OVOP_COUNT; i++) {
46827 if (opset->self_ops[i])
46828 JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
46829 mark_func);
46830 }
46831 for(j = 0; j < opset->left.count; j++) {
46832 ent = &opset->left.tab[j];
46833 for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46834 if (ent->ops[i])
46835 JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
46836 mark_func);
46837 }
46838 }
46839 for(j = 0; j < opset->right.count; j++) {
46840 ent = &opset->right.tab[j];
46841 for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46842 if (ent->ops[i])
46843 JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
46844 mark_func);
46845 }
46846 }
46847 }
46848}
46849
46850
46851/* create an OperatorSet object */
46852static JSValue js_operators_create_internal(JSContext *ctx,
46853 int argc, JSValueConst *argv,
46854 BOOL is_primitive)
46855{
46856 JSValue opset_obj, prop, obj;
46857 JSOperatorSetData *opset, *opset1;
46858 JSBinaryOperatorDef *def;
46859 JSValueConst arg;
46860 int i, j;
46861 JSBinaryOperatorDefEntry *new_tab;
46862 JSBinaryOperatorDefEntry *ent;
46863 uint32_t op_count;
46864
46865 if (ctx->rt->operator_count == UINT32_MAX) {
46866 return JS_ThrowTypeError(ctx, "too many operators");
46867 }
46868 opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
46869 if (JS_IsException(opset_obj))
46870 goto fail;
46871 opset = js_mallocz(ctx, sizeof(*opset));
46872 if (!opset)
46873 goto fail;
46874 JS_SetOpaque(opset_obj, opset);
46875 if (argc >= 1) {
46876 arg = argv[0];
46877 /* self operators */
46878 for(i = 0; i < JS_OVOP_COUNT; i++) {
46879 prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
46880 if (JS_IsException(prop))
46881 goto fail;
46882 if (!JS_IsUndefined(prop)) {
46883 if (check_function(ctx, prop)) {
46884 JS_FreeValue(ctx, prop);
46885 goto fail;
46886 }
46887 opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
46888 }
46889 }
46890 }
46891 /* left & right operators */
46892 for(j = 1; j < argc; j++) {
46893 arg = argv[j];
46894 prop = JS_GetPropertyStr(ctx, arg, "left");
46895 if (JS_IsException(prop))
46896 goto fail;
46897 def = &opset->right;
46898 if (JS_IsUndefined(prop)) {
46899 prop = JS_GetPropertyStr(ctx, arg, "right");
46900 if (JS_IsException(prop))
46901 goto fail;
46902 if (JS_IsUndefined(prop)) {
46903 JS_ThrowTypeError(ctx, "left or right property must be present");
46904 goto fail;
46905 }
46906 def = &opset->left;
46907 }
46908 /* get the operator set */
46909 obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
46910 JS_FreeValue(ctx, prop);
46911 if (JS_IsException(obj))
46912 goto fail;
46913 prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
46914 JS_FreeValue(ctx, obj);
46915 if (JS_IsException(prop))
46916 goto fail;
46917 opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
46918 if (!opset1) {
46919 JS_FreeValue(ctx, prop);
46920 goto fail;
46921 }
46922 op_count = opset1->operator_counter;
46923 JS_FreeValue(ctx, prop);
46924
46925 /* we assume there are few entries */
46926 new_tab = js_realloc(ctx, def->tab,
46927 (def->count + 1) * sizeof(def->tab[0]));
46928 if (!new_tab)
46929 goto fail;
46930 def->tab = new_tab;
46931 def->count++;
46932 ent = def->tab + def->count - 1;
46933 memset(ent, 0, sizeof(def->tab[0]));
46934 ent->operator_index = op_count;
46935
46936 for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46937 prop = JS_GetPropertyStr(ctx, arg,
46938 js_overloadable_operator_names[i]);
46939 if (JS_IsException(prop))
46940 goto fail;
46941 if (!JS_IsUndefined(prop)) {
46942 if (check_function(ctx, prop)) {
46943 JS_FreeValue(ctx, prop);
46944 goto fail;
46945 }
46946 ent->ops[i] = JS_VALUE_GET_OBJ(prop);
46947 }
46948 }
46949 }
46950 opset->is_primitive = is_primitive;
46951 opset->operator_counter = ctx->rt->operator_count++;
46952 return opset_obj;
46953 fail:
46954 JS_FreeValue(ctx, opset_obj);
46955 return JS_EXCEPTION;
46956}
46957
46958static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
46959 int argc, JSValueConst *argv)
46960{
46961 return js_operators_create_internal(ctx, argc, argv, FALSE);
46962}
46963
46964static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
46965 int argc, JSValueConst *argv)
46966{
46967 JSValue opset_obj, prop;
46968 JSOperatorSetData *opset;
46969 const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
46970 JSOverloadableOperatorEnum op;
46971 int i;
46972
46973 opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
46974 JS_ATOM_Symbol_operatorSet);
46975 if (JS_IsException(opset_obj))
46976 goto fail;
46977 opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
46978 if (!opset)
46979 goto fail;
46980 for(i = 0; i < countof(ops); i++) {
46981 op = ops[i];
46982 prop = JS_GetPropertyStr(ctx, argv[0],
46983 js_overloadable_operator_names[op]);
46984 if (JS_IsException(prop))
46985 goto fail;
46986 if (!JS_IsUndefined(prop)) {
46987 if (!JS_IsNull(prop) && check_function(ctx, prop)) {
46988 JS_FreeValue(ctx, prop);
46989 goto fail;
46990 }
46991 if (opset->self_ops[op])
46992 JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
46993 if (JS_IsNull(prop)) {
46994 opset->self_ops[op] = NULL;
46995 } else {
46996 opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
46997 }
46998 }
46999 }
47000 JS_FreeValue(ctx, opset_obj);
47001 return JS_UNDEFINED;
47002 fail:
47003 JS_FreeValue(ctx, opset_obj);
47004 return JS_EXCEPTION;
47005}
47006
47007static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
47008{
47009 JSValue opset_obj;
47010
47011 if (!JS_IsObject(obj)) /* in case the prototype is not defined */
47012 return 0;
47013 opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
47014 if (JS_IsException(opset_obj))
47015 return -1;
47016 /* cannot be modified by the user */
47017 JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
47018 opset_obj, 0);
47019 return 0;
47020}
47021
47022static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
47023 int argc, JSValueConst *argv)
47024{
47025 return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
47026}
47027
47028static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
47029 int argc, JSValueConst *argv)
47030{
47031 JSValue func_obj, proto, opset_obj;
47032
47033 func_obj = JS_UNDEFINED;
47034 proto = JS_NewObject(ctx);
47035 if (JS_IsException(proto))
47036 return JS_EXCEPTION;
47037 opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
47038 if (JS_IsException(opset_obj))
47039 goto fail;
47040 JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
47041 opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47042 func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
47043 0, JS_CFUNC_constructor, 0);
47044 if (JS_IsException(func_obj))
47045 goto fail;
47046 JS_SetConstructor2(ctx, func_obj, proto,
47047 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47048 JS_FreeValue(ctx, proto);
47049 return func_obj;
47050 fail:
47051 JS_FreeValue(ctx, proto);
47052 JS_FreeValue(ctx, func_obj);
47053 return JS_EXCEPTION;
47054}
47055
47056static const JSCFunctionListEntry js_operators_funcs[] = {
47057 JS_CFUNC_DEF("create", 1, js_operators_create ),
47058 JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
47059};
47060
47061/* must be called after all overloadable base types are initialized */
47062void JS_AddIntrinsicOperators(JSContext *ctx)
47063{
47064 JSValue obj;
47065
47066 ctx->allow_operator_overloading = TRUE;
47067 obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
47068 JS_SetPropertyFunctionList(ctx, obj,
47069 js_operators_funcs,
47070 countof(js_operators_funcs));
47071 JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
47072 obj,
47073 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47074 /* add default operatorSets */
47075 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
47076 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
47077 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
47078 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
47079 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
47080 js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
47081}
47082
47083/* BigInt */47083/* BigInt */
47084 47084
47085static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)47085static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
47086{47086{
47087 uint32_t tag;47087 uint32_t tag;
47088 BOOL is_legacy;
47089 int ret;
47090 47088
47091 is_legacy = is_bigint_mode(ctx) ^ 1;
47092 redo:47089 redo:
47093 tag = JS_VALUE_GET_NORM_TAG(val);47090 tag = JS_VALUE_GET_NORM_TAG(val);
47094 switch(tag) {47091 switch(tag) {
47095 case JS_TAG_INT:47092 case JS_TAG_INT:
47096 case JS_TAG_BOOL:47093 case JS_TAG_BOOL:
47097 if (is_legacy) {47094 val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
47098 bf_t r_s, *r = &r_s;
47099 bf_init(ctx->bf_ctx, r);
47100 bf_set_si(r, JS_VALUE_GET_INT(val));
47101 val = JS_NewBigInt2(ctx, r, TRUE);
47102 } else {
47103 val = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
47104 }
47105 break;47095 break;
47106 case JS_TAG_BIG_INT:47096 case JS_TAG_BIG_INT:
47107 break;47097 break;
47108 case JS_TAG_FLOAT64:47098 case JS_TAG_FLOAT64:
47109 case JS_TAG_BIG_FLOAT:47099 case JS_TAG_BIG_FLOAT:
47110 {47100 {
47111 bf_t *a, a_s, r_s, *r = &r_s;47101 bf_t *a, a_s;
47102
47112 a = JS_ToBigFloat(ctx, &a_s, val);47103 a = JS_ToBigFloat(ctx, &a_s, val);
47113 bf_init(ctx->bf_ctx, r);
47114 if (!bf_is_finite(a)) {47104 if (!bf_is_finite(a)) {
47115 JS_FreeValue(ctx, val);47105 JS_FreeValue(ctx, val);
47116 val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");47106 val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
47117 } else {47107 } else {
47118 bf_set(r, a);47108 JSValue val1 = JS_NewBigInt(ctx);
47119 ret = bf_rint(r, BF_RNDZ);47109 bf_t *r;
47110 int ret;
47111 if (JS_IsException(val1)) {
47112 JS_FreeValue(ctx, val);
47113 return JS_EXCEPTION;
47114 }
47115 r = JS_GetBigInt(val1);
47116 ret = bf_set(r, a);
47117 ret |= bf_rint(r, BF_RNDZ);
47120 JS_FreeValue(ctx, val);47118 JS_FreeValue(ctx, val);
47121 if (is_legacy && (ret & BF_ST_INEXACT)) {47119 if (ret & BF_ST_MEM_ERROR) {
47122 bf_delete(r);47120 JS_FreeValue(ctx, val1);
47121 val = JS_ThrowOutOfMemory(ctx);
47122 } else if (ret & BF_ST_INEXACT) {
47123 JS_FreeValue(ctx, val1);
47123 val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");47124 val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
47124 } else {47125 } else {
47125 val = JS_NewBigInt2(ctx, r, is_legacy);47126 val = JS_CompactBigInt(ctx, val1);
47126 }47127 }
47127 }47128 }
47128 if (a == &a_s)47129 if (a == &a_s)
47129 bf_delete(a);47130 bf_delete(a);
47130 }47131 }
47131 break;47132 break;
47133 case JS_TAG_BIG_DECIMAL:
47134 val = JS_ToStringFree(ctx, val);
47135 if (JS_IsException(val))
47136 break;
47137 goto redo;
47132 case JS_TAG_STRING:47138 case JS_TAG_STRING:
47133 val = JS_StringToBigIntErr(ctx, val);47139 val = JS_StringToBigIntErr(ctx, val);
47134 break;47140 break;
47135 case JS_TAG_OBJECT:47141 case JS_TAG_OBJECT:
47136 val = JS_ToPrimitiveFree(ctx, val,47142 val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
47137 is_legacy ? HINT_NUMBER : HINT_INTEGER);
47138 if (JS_IsException(val))47143 if (JS_IsException(val))
47139 break;47144 break;
47140 goto redo;47145 goto redo;
@@ -47154,17 +47159,6 @@ static JSValue js_bigint_constructor(JSContext *ctx, · 13 unmodified lines
47154 return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));47159 return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
47155}47160}
47156 47161
47157static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
47158{
47159 int tag = JS_VALUE_GET_TAG(v);
47160 if (tag == JS_TAG_BIG_INT)
47161 return TRUE;
47162 if (is_bigint_mode(ctx))
47163 return tag == JS_TAG_INT;
47164 else
47165 return FALSE;
47166}
47167
47168static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)47162static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
47169{47163{
47170 if (JS_IsBigInt(ctx, this_val))47164 if (JS_IsBigInt(ctx, this_val))
@@ -47173,8 +47167,6 @@ static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) · 2 unmodified lines
47173 if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {47167 if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
47174 JSObject *p = JS_VALUE_GET_OBJ(this_val);47168 JSObject *p = JS_VALUE_GET_OBJ(this_val);
47175 if (p->class_id == JS_CLASS_BIG_INT) {47169 if (p->class_id == JS_CLASS_BIG_INT) {
47176 /* XXX: may relax the check in case the object comes from
47177 bignum mode */
47178 if (JS_IsBigInt(ctx, p->u.object_data))47170 if (JS_IsBigInt(ctx, p->u.object_data))
47179 return JS_DupValue(ctx, p->u.object_data);47171 return JS_DupValue(ctx, p->u.object_data);
47180 }47172 }
@@ -47195,12 +47187,9 @@ static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val, · 14 unmodified lines
47195 if (argc == 0 || JS_IsUndefined(argv[0])) {47187 if (argc == 0 || JS_IsUndefined(argv[0])) {
47196 base = 10;47188 base = 10;
47197 } else {47189 } else {
47198 if (JS_ToInt32Sat(ctx, &base, argv[0]))47190 base = js_get_radix(ctx, argv[0]);
47191 if (base < 0)
47199 goto fail;47192 goto fail;
47200 if (base < 2 || base > 36) {
47201 JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
47202 goto fail;
47203 }
47204 }47193 }
47205 ret = js_bigint_to_string1(ctx, val, base);47194 ret = js_bigint_to_string1(ctx, val, base);
47206 JS_FreeValue(ctx, val);47195 JS_FreeValue(ctx, val);
@@ -47220,72 +47209,96 @@ static JSValue js_bigint_div(JSContext *ctx, · 13 unmodified lines
47220 JSValueConst this_val,47209 JSValueConst this_val,
47221 int argc, JSValueConst *argv, int magic)47210 int argc, JSValueConst *argv, int magic)
47222{47211{
47223 bf_t a_s, b_s, *a, *b, r_s, *r = &r_s, q_s, *q = &q_s;47212 bf_t a_s, b_s, *a, *b, *r, *q;
47224 int status;47213 int status;
47225 47214 JSValue q_val, r_val;
47215
47216 q_val = JS_NewBigInt(ctx);
47217 if (JS_IsException(q_val))
47218 return JS_EXCEPTION;
47219 r_val = JS_NewBigInt(ctx);
47220 if (JS_IsException(r_val))
47221 goto fail;
47226 b = NULL;47222 b = NULL;
47227 a = JS_ToBigInt(ctx, &a_s, argv[0]);47223 a = JS_ToBigInt(ctx, &a_s, argv[0]);
47228 if (!a)47224 if (!a)
47229 return JS_EXCEPTION;47225 goto fail;
47230 b = JS_ToBigInt(ctx, &b_s, argv[1]);47226 b = JS_ToBigInt(ctx, &b_s, argv[1]);
47231 if (!b) {47227 if (!b) {
47232 JS_FreeBigInt(ctx, a, &a_s);47228 JS_FreeBigInt(ctx, a, &a_s);
47233 return JS_EXCEPTION;47229 goto fail;
47234 }47230 }
47235 bf_init(ctx->bf_ctx, q);47231 q = JS_GetBigInt(q_val);
47236 bf_init(ctx->bf_ctx, r);47232 r = JS_GetBigInt(r_val);
47237 status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);47233 status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
47238 JS_FreeBigInt(ctx, a, &a_s);47234 JS_FreeBigInt(ctx, a, &a_s);
47239 JS_FreeBigInt(ctx, b, &b_s);47235 JS_FreeBigInt(ctx, b, &b_s);
47240 if (unlikely(status)) {47236 if (unlikely(status)) {
47241 bf_delete(q);
47242 bf_delete(r);
47243 throw_bf_exception(ctx, status);47237 throw_bf_exception(ctx, status);
47244 return JS_EXCEPTION;47238 goto fail;
47245 }47239 }
47240 q_val = JS_CompactBigInt(ctx, q_val);
47246 if (magic & 0x10) {47241 if (magic & 0x10) {
47247 JSValue ret;47242 JSValue ret;
47248 /* XXX: handle exceptions */
47249 ret = JS_NewArray(ctx);47243 ret = JS_NewArray(ctx);
47250 JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, q));47244 if (JS_IsException(ret))
47251 JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, r));47245 goto fail;
47246 JS_SetPropertyUint32(ctx, ret, 0, q_val);
47247 JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
47252 return ret;47248 return ret;
47253 } else {47249 } else {
47254 bf_delete(r);47250 JS_FreeValue(ctx, r_val);
47255 return JS_NewBigInt(ctx, q);47251 return q_val;
47256 }47252 }
47253 fail:
47254 JS_FreeValue(ctx, q_val);
47255 JS_FreeValue(ctx, r_val);
47256 return JS_EXCEPTION;
47257}47257}
47258 47258
47259static JSValue js_bigint_sqrt(JSContext *ctx,47259static JSValue js_bigint_sqrt(JSContext *ctx,
47260 JSValueConst this_val,47260 JSValueConst this_val,
47261 int argc, JSValueConst *argv, int magic)47261 int argc, JSValueConst *argv, int magic)
47262{47262{
47263 bf_t a_s, *a, r_s, *r = &r_s, rem_s, *rem = &rem_s;47263 bf_t a_s, *a, *r, *rem;
47264 int status;47264 int status;
47265 JSValue r_val, rem_val;
47266
47267 r_val = JS_NewBigInt(ctx);
47268 if (JS_IsException(r_val))
47269 return JS_EXCEPTION;
47270 rem_val = JS_NewBigInt(ctx);
47271 if (JS_IsException(rem_val))
47272 return JS_EXCEPTION;
47273 r = JS_GetBigInt(r_val);
47274 rem = JS_GetBigInt(rem_val);
47265 47275
47266 a = JS_ToBigInt(ctx, &a_s, argv[0]);47276 a = JS_ToBigInt(ctx, &a_s, argv[0]);
47267 if (!a)47277 if (!a)
47268 return JS_EXCEPTION;47278 goto fail;
47269 bf_init(ctx->bf_ctx, r);
47270 bf_init(ctx->bf_ctx, rem);
47271 status = bf_sqrtrem(r, rem, a);47279 status = bf_sqrtrem(r, rem, a);
47272 JS_FreeBigInt(ctx, a, &a_s);47280 JS_FreeBigInt(ctx, a, &a_s);
47273 if (unlikely(status & ~BF_ST_INEXACT)) {47281 if (unlikely(status & ~BF_ST_INEXACT)) {
47274 bf_delete(r);47282 throw_bf_exception(ctx, status);
47275 bf_delete(rem);47283 goto fail;
47276 return throw_bf_exception(ctx, status);
47277 }47284 }
47285 r_val = JS_CompactBigInt(ctx, r_val);
47278 if (magic) {47286 if (magic) {
47279 JSValue ret;47287 JSValue ret;
47280 /* XXX: handle exceptions */
47281 ret = JS_NewArray(ctx);47288 ret = JS_NewArray(ctx);
47282 JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, r));47289 if (JS_IsException(ret))
47283 JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, rem));47290 goto fail;
47291 JS_SetPropertyUint32(ctx, ret, 0, r_val);
47292 JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
47284 return ret;47293 return ret;
47285 } else {47294 } else {
47286 bf_delete(rem);47295 JS_FreeValue(ctx, rem_val);
47287 return JS_NewBigInt(ctx, r);47296 return r_val;
47288 }47297 }
47298 fail:
47299 JS_FreeValue(ctx, r_val);
47300 JS_FreeValue(ctx, rem_val);
47301 return JS_EXCEPTION;
47289}47302}
47290 47303
47291static JSValue js_bigint_op1(JSContext *ctx,47304static JSValue js_bigint_op1(JSContext *ctx,
@@ -47326,15 +47339,22 @@ static JSValue js_bigint_asUintN(JSContext *ctx, · 34 unmodified lines
47326 int argc, JSValueConst *argv, int asIntN)47339 int argc, JSValueConst *argv, int asIntN)
47327{47340{
47328 uint64_t bits;47341 uint64_t bits;
47329 bf_t a_s, *a = &a_s, r_s, *r = &r_s, mask_s, *mask = &mask_s;47342 bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
47330 47343 JSValue res;
47344
47331 if (JS_ToIndex(ctx, &bits, argv[0]))47345 if (JS_ToIndex(ctx, &bits, argv[0]))
47332 return JS_EXCEPTION;47346 return JS_EXCEPTION;
47347 res = JS_NewBigInt(ctx);
47348 if (JS_IsException(res))
47349 return JS_EXCEPTION;
47350 r = JS_GetBigInt(res);
47333 a = JS_ToBigInt(ctx, &a_s, argv[1]);47351 a = JS_ToBigInt(ctx, &a_s, argv[1]);
47334 if (!a)47352 if (!a) {
47353 JS_FreeValue(ctx, res);
47335 return JS_EXCEPTION;47354 return JS_EXCEPTION;
47355 }
47336 /* XXX: optimize */47356 /* XXX: optimize */
47337 bf_init(ctx->bf_ctx, r);47357 r = JS_GetBigInt(res);
47338 bf_init(ctx->bf_ctx, mask);47358 bf_init(ctx->bf_ctx, mask);
47339 bf_set_ui(mask, 1);47359 bf_set_ui(mask, 1);
47340 bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);47360 bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
@@ -47351,7 +47371,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, · 10 unmodified lines
47351 }47371 }
47352 bf_delete(mask);47372 bf_delete(mask);
47353 JS_FreeBigInt(ctx, a, &a_s);47373 JS_FreeBigInt(ctx, a, &a_s);
47354 return JS_NewBigInt(ctx, r);47374 return JS_CompactBigInt(ctx, res);
47355}47375}
47356 47376
47357static const JSCFunctionListEntry js_bigint_funcs[] = {47377static const JSCFunctionListEntry js_bigint_funcs[] = {
@@ -47430,12 +47450,9 @@ static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val, · 72 unmodified lines
47430 if (argc == 0 || JS_IsUndefined(argv[0])) {47450 if (argc == 0 || JS_IsUndefined(argv[0])) {
47431 base = 10;47451 base = 10;
47432 } else {47452 } else {
47433 if (JS_ToInt32Sat(ctx, &base, argv[0]))47453 base = js_get_radix(ctx, argv[0]);
47434 goto fail;47454 if (base < 0)
47435 if (base < 2 || base > 36) {
47436 JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
47437 goto fail;47455 goto fail;
47438 }
47439 }47456 }
47440 ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);47457 ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
47441 JS_FreeValue(ctx, val);47458 JS_FreeValue(ctx, val);
@@ -47451,7 +47468,7 @@ static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val, · 9 unmodified lines
47451 return js_thisBigFloatValue(ctx, this_val);47468 return js_thisBigFloatValue(ctx, this_val);
47452}47469}
47453 47470
47454static int get_rnd_mode(JSContext *ctx, JSValueConst val)47471static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
47455{47472{
47456 int rnd_mode;47473 int rnd_mode;
47457 if (JS_ToInt32Sat(ctx, &rnd_mode, val))47474 if (JS_ToInt32Sat(ctx, &rnd_mode, val))
@@ -47468,8 +47485,7 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
47468{47485{
47469 JSValue val, ret;47486 JSValue val, ret;
47470 int64_t f;47487 int64_t f;
47471 int res, rnd_mode;47488 int rnd_mode, radix;
47472 bf_t a_s, *a, b;
47473 47489
47474 val = js_thisBigFloatValue(ctx, this_val);47490 val = js_thisBigFloatValue(ctx, this_val);
47475 if (JS_IsException(val))47491 if (JS_IsException(val))
@@ -47481,26 +47497,19 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, · 5 unmodified lines
47481 goto fail;47497 goto fail;
47482 }47498 }
47483 rnd_mode = BF_RNDNA;47499 rnd_mode = BF_RNDNA;
47500 radix = 10;
47501 /* XXX: swap parameter order for rounding mode and radix */
47484 if (argc > 1) {47502 if (argc > 1) {
47485 rnd_mode = get_rnd_mode(ctx, argv[1]);47503 rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
47486 if (rnd_mode < 0)47504 if (rnd_mode < 0)
47487 goto fail;47505 goto fail;
47488 }47506 }
47489 47507 if (argc > 2) {
47490 a = JS_ToBigFloat(ctx, &a_s, val);47508 radix = js_get_radix(ctx, argv[2]);
47491 if (!a)47509 if (radix < 0)
47492 goto fail;47510 goto fail;
47493 bf_init(ctx->bf_ctx, &b);
47494 bf_set_float64(&b, 1e21);
47495 res = bf_cmpu(a, &b);
47496 bf_delete(&b);
47497 if (a == &a_s)
47498 bf_delete(a);
47499 if (res >= 0) {
47500 ret = JS_ToString(ctx, val);
47501 } else {
47502 ret = js_ftoa(ctx, val, 10, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
47503 }47511 }
47512 ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
47504 JS_FreeValue(ctx, val);47513 JS_FreeValue(ctx, val);
47505 return ret;47514 return ret;
47506 fail:47515 fail:
@@ -47533,7 +47542,7 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, · 26 unmodified lines
47533{47542{
47534 JSValue val, ret;47543 JSValue val, ret;
47535 int64_t f;47544 int64_t f;
47536 int rnd_mode;47545 int rnd_mode, radix;
47537 47546
47538 val = js_thisBigFloatValue(ctx, this_val);47547 val = js_thisBigFloatValue(ctx, this_val);
47539 if (JS_IsException(val))47548 if (JS_IsException(val))
@@ -47551,12 +47560,18 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
47551 goto fail;47560 goto fail;
47552 }47561 }
47553 rnd_mode = BF_RNDNA;47562 rnd_mode = BF_RNDNA;
47563 radix = 10;
47554 if (argc > 1) {47564 if (argc > 1) {
47555 rnd_mode = get_rnd_mode(ctx, argv[1]);47565 rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
47556 if (rnd_mode < 0)47566 if (rnd_mode < 0)
47557 goto fail;47567 goto fail;
47558 }47568 }
47559 ret = js_ftoa(ctx, val, 10, f + 1,47569 if (argc > 2) {
47570 radix = js_get_radix(ctx, argv[2]);
47571 if (radix < 0)
47572 goto fail;
47573 }
47574 ret = js_ftoa(ctx, val, radix, f + 1,
47560 rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);47575 rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
47561 }47576 }
47562 JS_FreeValue(ctx, val);47577 JS_FreeValue(ctx, val);
@@ -47571,7 +47586,7 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, · 8 unmodified lines
47571{47586{
47572 JSValue val, ret;47587 JSValue val, ret;
47573 int64_t p;47588 int64_t p;
47574 int rnd_mode;47589 int rnd_mode, radix;
47575 47590
47576 val = js_thisBigFloatValue(ctx, this_val);47591 val = js_thisBigFloatValue(ctx, this_val);
47577 if (JS_IsException(val))47592 if (JS_IsException(val))
@@ -47589,12 +47604,18 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
47589 goto fail;47604 goto fail;
47590 }47605 }
47591 rnd_mode = BF_RNDNA;47606 rnd_mode = BF_RNDNA;
47607 radix = 10;
47592 if (argc > 1) {47608 if (argc > 1) {
47593 rnd_mode = get_rnd_mode(ctx, argv[1]);47609 rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
47594 if (rnd_mode < 0)47610 if (rnd_mode < 0)
47595 goto fail;47611 goto fail;
47596 }47612 }
47597 ret = js_ftoa(ctx, val, 10, p, rnd_mode | BF_FTOA_FORMAT_FIXED);47613 if (argc > 2) {
47614 radix = js_get_radix(ctx, argv[2]);
47615 if (radix < 0)
47616 goto fail;
47617 }
47618 ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
47598 }47619 }
47599 JS_FreeValue(ctx, val);47620 JS_FreeValue(ctx, val);
47600 return ret;47621 return ret;
@@ -47617,10 +47638,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 16 unmodified lines
47617{47638{
47618 JSValue val;47639 JSValue val;
47619 if (argc == 0) {47640 if (argc == 0) {
47620 bf_t r_s, *r = &r_s;47641 bf_t *r;
47621 bf_init(ctx->bf_ctx, r);47642 val = JS_NewBigFloat(ctx);
47643 if (JS_IsException(val))
47644 return val;
47645 r = JS_GetBigFloat(val);
47622 bf_set_zero(r, 0);47646 bf_set_zero(r, 0);
47623 val = JS_NewBigFloat(ctx, r);
47624 } else {47647 } else {
47625 val = JS_DupValue(ctx, argv[0]);47648 val = JS_DupValue(ctx, argv[0]);
47626 redo:47649 redo:
@@ -47629,18 +47652,26 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 2 unmodified lines
47629 break;47652 break;
47630 case JS_TAG_FLOAT64:47653 case JS_TAG_FLOAT64:
47631 {47654 {
47632 bf_t r_s, *r = &r_s;47655 bf_t *r;
47633 bf_init(ctx->bf_ctx, r);47656 double d = JS_VALUE_GET_FLOAT64(val);
47634 bf_set_float64(r, JS_VALUE_GET_FLOAT64(val));47657 val = JS_NewBigFloat(ctx);
47635 val = JS_NewBigFloat(ctx, r);47658 if (JS_IsException(val))
47659 break;
47660 r = JS_GetBigFloat(val);
47661 if (bf_set_float64(r, d))
47662 goto fail;
47636 }47663 }
47637 break;47664 break;
47638 case JS_TAG_INT:47665 case JS_TAG_INT:
47639 {47666 {
47640 bf_t r_s, *r = &r_s;47667 bf_t *r;
47641 bf_init(ctx->bf_ctx, r);47668 int32_t v = JS_VALUE_GET_INT(val);
47642 bf_set_si(r, JS_VALUE_GET_INT(val));47669 val = JS_NewBigFloat(ctx);
47643 val = JS_NewBigFloat(ctx, r);47670 if (JS_IsException(val))
47671 break;
47672 r = JS_GetBigFloat(val);
47673 if (bf_set_si(r, v))
47674 goto fail;
47644 }47675 }
47645 break;47676 break;
47646 case JS_TAG_BIG_INT:47677 case JS_TAG_BIG_INT:
@@ -47650,6 +47681,11 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 3 unmodified lines
47650 val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);47681 val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
47651 }47682 }
47652 break;47683 break;
47684 case JS_TAG_BIG_DECIMAL:
47685 val = JS_ToStringFree(ctx, val);
47686 if (JS_IsException(val))
47687 break;
47688 goto redo;
47653 case JS_TAG_STRING:47689 case JS_TAG_STRING:
47654 {47690 {
47655 const char *str, *p;47691 const char *str, *p;
@@ -47663,10 +47699,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 7 unmodified lines
47663 p = str;47699 p = str;
47664 p += skip_spaces(p);47700 p += skip_spaces(p);
47665 if ((p - str) == len) {47701 if ((p - str) == len) {
47666 bf_t r_s, *r = &r_s;47702 bf_t *r;
47667 bf_init(ctx->bf_ctx, r);47703 val = JS_NewBigFloat(ctx);
47668 bf_set_si(r, 0);47704 if (JS_IsException(val))
47669 val = JS_NewBigFloat(ctx, r);47705 break;
47706 r = JS_GetBigFloat(val);
47707 bf_set_zero(r, 0);
47670 err = 0;47708 err = 0;
47671 } else {47709 } else {
47672 val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |47710 val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
@@ -47699,13 +47737,20 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 26 unmodified lines
47699 }47737 }
47700 }47738 }
47701 return val;47739 return val;
47740 fail:
47741 JS_FreeValue(ctx, val);
47742 return JS_EXCEPTION;
47702}47743}
47703 47744
47704static JSValue js_bigfloat_get_const(JSContext *ctx,47745static JSValue js_bigfloat_get_const(JSContext *ctx,
47705 JSValueConst this_val, int magic)47746 JSValueConst this_val, int magic)
47706{47747{
47707 bf_t r_s, *r = &r_s;47748 bf_t *r;
47708 bf_init(ctx->bf_ctx, r);47749 JSValue val;
47750 val = JS_NewBigFloat(ctx);
47751 if (JS_IsException(val))
47752 return val;
47753 r = JS_GetBigFloat(val);
47709 switch(magic) {47754 switch(magic) {
47710 case 0: /* PI */47755 case 0: /* PI */
47711 bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);47756 bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
@@ -47741,13 +47786,13 @@ static JSValue js_bigfloat_get_const(JSContext *ctx, · 29 unmodified lines
47741 default:47786 default:
47742 abort();47787 abort();
47743 }47788 }
47744 return JS_NewBigFloat(ctx, r);47789 return val;
47745}47790}
47746 47791
47747static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,47792static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
47748 int argc, JSValueConst *argv)47793 int argc, JSValueConst *argv)
47749{47794{
47750 bf_t a_s, *a = &a_s;47795 bf_t *a;
47751 const char *str;47796 const char *str;
47752 JSValue ret;47797 JSValue ret;
47753 int radix;47798 int radix;
@@ -47771,10 +47816,13 @@ static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val, · 17 unmodified lines
47771 if (!fe)47816 if (!fe)
47772 goto fail;47817 goto fail;
47773 }47818 }
47774 bf_init(ctx->bf_ctx, a);47819 ret = JS_NewBigFloat(ctx);
47820 if (JS_IsException(ret))
47821 goto done;
47822 a = JS_GetBigFloat(ret);
47775 /* XXX: use js_atof() */47823 /* XXX: use js_atof() */
47776 bf_atof(a, str, NULL, radix, fe->prec, fe->flags);47824 bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
47777 ret = JS_NewBigFloat(ctx, a);47825 done:
47778 JS_FreeCString(ctx, str);47826 JS_FreeCString(ctx, str);
47779 return ret;47827 return ret;
47780}47828}
@@ -47800,7 +47848,201 @@ static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, · 19 unmodified lines
47800 if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)47848 if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
47801 return JS_FALSE;47849 return JS_FALSE;
47802 p = JS_VALUE_GET_PTR(val);47850 p = JS_VALUE_GET_PTR(val);
47803 return JS_NewBool(ctx, bf_is_finite(&p->num));47851 return JS_NewBool(ctx, bf_is_nan(&p->num));
47852}
47853
47854enum {
47855 MATH_OP_ABS,
47856 MATH_OP_FLOOR,
47857 MATH_OP_CEIL,
47858 MATH_OP_ROUND,
47859 MATH_OP_TRUNC,
47860 MATH_OP_SQRT,
47861 MATH_OP_FPROUND,
47862 MATH_OP_ACOS,
47863 MATH_OP_ASIN,
47864 MATH_OP_ATAN,
47865 MATH_OP_ATAN2,
47866 MATH_OP_COS,
47867 MATH_OP_EXP,
47868 MATH_OP_LOG,
47869 MATH_OP_POW,
47870 MATH_OP_SIN,
47871 MATH_OP_TAN,
47872 MATH_OP_FMOD,
47873 MATH_OP_REM,
47874 MATH_OP_SIGN,
47875
47876 MATH_OP_ADD,
47877 MATH_OP_SUB,
47878 MATH_OP_MUL,
47879 MATH_OP_DIV,
47880};
47881
47882static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
47883 int argc, JSValueConst *argv, int magic)
47884{
47885 bf_t a_s, *a, *r;
47886 JSFloatEnv *fe;
47887 int rnd_mode;
47888 JSValue op1, res;
47889
47890 op1 = JS_ToNumeric(ctx, argv[0]);
47891 if (JS_IsException(op1))
47892 return op1;
47893 a = JS_ToBigFloat(ctx, &a_s, op1);
47894 fe = &ctx->fp_env;
47895 if (argc > 1) {
47896 fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
47897 if (!fe)
47898 goto fail;
47899 }
47900 res = JS_NewBigFloat(ctx);
47901 if (JS_IsException(res)) {
47902 fail:
47903 if (a == &a_s)
47904 bf_delete(a);
47905 JS_FreeValue(ctx, op1);
47906 return JS_EXCEPTION;
47907 }
47908 r = JS_GetBigFloat(res);
47909 switch (magic) {
47910 case MATH_OP_ABS:
47911 bf_set(r, a);
47912 r->sign = 0;
47913 break;
47914 case MATH_OP_FLOOR:
47915 rnd_mode = BF_RNDD;
47916 goto rint;
47917 case MATH_OP_CEIL:
47918 rnd_mode = BF_RNDU;
47919 goto rint;
47920 case MATH_OP_ROUND:
47921 rnd_mode = BF_RNDNA;
47922 goto rint;
47923 case MATH_OP_TRUNC:
47924 rnd_mode = BF_RNDZ;
47925 rint:
47926 bf_set(r, a);
47927 fe->status |= bf_rint(r, rnd_mode);
47928 break;
47929 case MATH_OP_SQRT:
47930 fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
47931 break;
47932 case MATH_OP_FPROUND:
47933 bf_set(r, a);
47934 fe->status |= bf_round(r, fe->prec, fe->flags);
47935 break;
47936 case MATH_OP_ACOS:
47937 fe->status |= bf_acos(r, a, fe->prec, fe->flags);
47938 break;
47939 case MATH_OP_ASIN:
47940 fe->status |= bf_asin(r, a, fe->prec, fe->flags);
47941 break;
47942 case MATH_OP_ATAN:
47943 fe->status |= bf_atan(r, a, fe->prec, fe->flags);
47944 break;
47945 case MATH_OP_COS:
47946 fe->status |= bf_cos(r, a, fe->prec, fe->flags);
47947 break;
47948 case MATH_OP_EXP:
47949 fe->status |= bf_exp(r, a, fe->prec, fe->flags);
47950 break;
47951 case MATH_OP_LOG:
47952 fe->status |= bf_log(r, a, fe->prec, fe->flags);
47953 break;
47954 case MATH_OP_SIN:
47955 fe->status |= bf_sin(r, a, fe->prec, fe->flags);
47956 break;
47957 case MATH_OP_TAN:
47958 fe->status |= bf_tan(r, a, fe->prec, fe->flags);
47959 break;
47960 case MATH_OP_SIGN:
47961 if (bf_is_nan(a) || bf_is_zero(a)) {
47962 bf_set(r, a);
47963 } else {
47964 bf_set_si(r, 1 - 2 * a->sign);
47965 }
47966 break;
47967 default:
47968 abort();
47969 }
47970 if (a == &a_s)
47971 bf_delete(a);
47972 JS_FreeValue(ctx, op1);
47973 return res;
47974}
47975
47976static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
47977 int argc, JSValueConst *argv, int magic)
47978{
47979 bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
47980 JSFloatEnv *fe;
47981 JSValue op1, op2, res;
47982
47983 op1 = JS_ToNumeric(ctx, argv[0]);
47984 if (JS_IsException(op1))
47985 return op1;
47986 op2 = JS_ToNumeric(ctx, argv[1]);
47987 if (JS_IsException(op2)) {
47988 JS_FreeValue(ctx, op1);
47989 return op2;
47990 }
47991 a = JS_ToBigFloat(ctx, &a_s, op1);
47992 b = JS_ToBigFloat(ctx, &b_s, op2);
47993 fe = &ctx->fp_env;
47994 if (argc > 2) {
47995 fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
47996 if (!fe)
47997 goto fail;
47998 }
47999 res = JS_NewBigFloat(ctx);
48000 if (JS_IsException(res)) {
48001 fail:
48002 if (a == &a_s)
48003 bf_delete(a);
48004 if (b == &b_s)
48005 bf_delete(b);
48006 JS_FreeValue(ctx, op1);
48007 JS_FreeValue(ctx, op2);
48008 return JS_EXCEPTION;
48009 }
48010 r = JS_GetBigFloat(res);
48011 switch (magic) {
48012 case MATH_OP_ATAN2:
48013 fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
48014 break;
48015 case MATH_OP_POW:
48016 fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
48017 break;
48018 case MATH_OP_FMOD:
48019 fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
48020 break;
48021 case MATH_OP_REM:
48022 fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
48023 break;
48024 case MATH_OP_ADD:
48025 fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
48026 break;
48027 case MATH_OP_SUB:
48028 fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
48029 break;
48030 case MATH_OP_MUL:
48031 fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
48032 break;
48033 case MATH_OP_DIV:
48034 fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
48035 break;
48036 default:
48037 abort();
48038 }
48039 if (a == &a_s)
48040 bf_delete(a);
48041 if (b == &b_s)
48042 bf_delete(b);
48043 JS_FreeValue(ctx, op1);
48044 JS_FreeValue(ctx, op2);
48045 return res;
47804}48046}
47805 48047
47806static const JSCFunctionListEntry js_bigfloat_funcs[] = {48048static const JSCFunctionListEntry js_bigfloat_funcs[] = {
@@ -47895,9 +48137,6 @@ static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val) · 88 unmodified lines
47895 return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));48137 return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
47896}48138}
47897 48139
47898/* temporary fix for string conversion overflows */
47899#define BF_EXP_BITS_MAX1 (BF_EXP_BITS_MAX - 1)
47900
47901static JSValue js_float_env_setPrec(JSContext *ctx,48140static JSValue js_float_env_setPrec(JSContext *ctx,
47902 JSValueConst this_val,48141 JSValueConst this_val,
47903 int argc, JSValueConst *argv)48142 int argc, JSValueConst *argv)
@@ -47913,18 +48152,16 @@ static JSValue js_float_env_setPrec(JSContext *ctx, · 9 unmodified lines
47913 return JS_EXCEPTION;48152 return JS_EXCEPTION;
47914 if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)48153 if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
47915 return JS_ThrowRangeError(ctx, "invalid precision");48154 return JS_ThrowRangeError(ctx, "invalid precision");
47916 exp_bits = BF_EXP_BITS_MAX1;48155 exp_bits = BF_EXP_BITS_MAX;
47917 48156
47918 if (argc > 2 && !JS_IsUndefined(argv[2])) {48157 if (argc > 2 && !JS_IsUndefined(argv[2])) {
47919 if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))48158 if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
47920 return JS_EXCEPTION;48159 return JS_EXCEPTION;
47921 if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX1)48160 if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
47922 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");48161 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
47923 }48162 }
47924 48163
47925 flags = BF_RNDN | bf_set_exp_bits(exp_bits);48164 flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
47926 if (exp_bits != BF_EXP_BITS_MAX1)
47927 flags |= BF_FLAG_SUBNORMAL;
47928 48165
47929 saved_prec = ctx->fp_env.prec;48166 saved_prec = ctx->fp_env.prec;
47930 saved_flags = ctx->fp_env.flags;48167 saved_flags = ctx->fp_env.flags;
@@ -47984,24 +48221,20 @@ static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_v · 53 unmodified lines
47984 case FE_EXP:48221 case FE_EXP:
47985 if (JS_ToInt32Sat(ctx, &b, val))48222 if (JS_ToInt32Sat(ctx, &b, val))
47986 return JS_EXCEPTION;48223 return JS_EXCEPTION;
47987 if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX1)48224 if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
47988 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");48225 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
47989 if (b == BF_EXP_BITS_MAX1)
47990 fe->flags &= ~BF_FLAG_SUBNORMAL;
47991 fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |48226 fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
47992 bf_set_exp_bits(b);48227 bf_set_exp_bits(b);
47993 break;48228 break;
47994 case FE_RNDMODE:48229 case FE_RNDMODE:
47995 b = get_rnd_mode(ctx, val);48230 b = bigfloat_get_rnd_mode(ctx, val);
47996 if (b < 0)48231 if (b < 0)
47997 return JS_EXCEPTION;48232 return JS_EXCEPTION;
47998 fe->flags = (fe->flags & ~BF_RND_MASK) | b;48233 fe->flags = (fe->flags & ~BF_RND_MASK) | b;
47999 break;48234 break;
48000 case FE_SUBNORMAL:48235 case FE_SUBNORMAL:
48001 b = JS_ToBool(ctx, val);48236 b = JS_ToBool(ctx, val);
48002 if (bf_get_exp_bits(fe->flags) != BF_EXP_BITS_MAX1) {48237 fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
48003 fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
48004 }
48005 break;48238 break;
48006 default:48239 default:
48007 b = JS_ToBool(ctx, val);48240 b = JS_ToBool(ctx, val);
@@ -48031,12 +48264,12 @@ static const JSCFunctionListEntry js_float_env_funcs[] = { · 23 unmodified lines
48031 JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),48264 JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
48032 JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),48265 JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
48033 JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),48266 JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
48034 JS_PROP_INT32_DEF("RNDNU", BF_RNDNU, 0 ),48267 JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
48035 JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),48268 JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
48036 JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),48269 JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
48037 JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),48270 JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
48038 JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),48271 JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
48039 JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX1, 0 ),48272 JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
48040};48273};
48041 48274
48042static const JSCFunctionListEntry js_float_env_proto_funcs[] = {48275static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
@@ -48112,10 +48345,18 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 69 unmodified lines
48112 case JS_TAG_BOOL:48345 case JS_TAG_BOOL:
48113 case JS_TAG_INT:48346 case JS_TAG_INT:
48114 {48347 {
48115 bfdec_t r_s, *r = &r_s;48348 bfdec_t *r;
48116 bfdec_init(ctx->bf_ctx, r);48349 int32_t v = JS_VALUE_GET_INT(val);
48117 bfdec_set_si(r, JS_VALUE_GET_INT(val));48350
48118 val = JS_NewBigDecimal(ctx, r);48351 val = JS_NewBigDecimal(ctx);
48352 if (JS_IsException(val))
48353 break;
48354 r = JS_GetBigDecimal(val);
48355 if (bfdec_set_si(r, v)) {
48356 JS_FreeValue(ctx, val);
48357 val = JS_EXCEPTION;
48358 break;
48359 }
48119 }48360 }
48120 break;48361 break;
48121 case JS_TAG_FLOAT64:48362 case JS_TAG_FLOAT64:
@@ -48138,10 +48379,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 16 unmodified lines
48138 p = str;48379 p = str;
48139 p += skip_spaces(p);48380 p += skip_spaces(p);
48140 if ((p - str) == len) {48381 if ((p - str) == len) {
48141 bfdec_t r_s, *r = &r_s;48382 bfdec_t *r;
48142 bfdec_init(ctx->bf_ctx, r);48383 val = JS_NewBigDecimal(ctx);
48384 if (JS_IsException(val))
48385 break;
48386 r = JS_GetBigDecimal(val);
48143 bfdec_set_zero(r, 0);48387 bfdec_set_zero(r, 0);
48144 val = JS_NewBigDecimal(ctx, r);
48145 err = 0;48388 err = 0;
48146 } else {48389 } else {
48147 val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);48390 val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
@@ -48166,12 +48409,14 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 18 unmodified lines
48166 goto redo;48409 goto redo;
48167 case JS_TAG_UNDEFINED:48410 case JS_TAG_UNDEFINED:
48168 {48411 {
48169 bfdec_t r_s, *r = &r_s;48412 bfdec_t *r;
48170 if (!allow_null_or_undefined)48413 if (!allow_null_or_undefined)
48171 goto fail;48414 goto fail;
48172 bfdec_init(ctx->bf_ctx, r);48415 val = JS_NewBigDecimal(ctx);
48416 if (JS_IsException(val))
48417 break;
48418 r = JS_GetBigDecimal(val);
48173 bfdec_set_nan(r);48419 bfdec_set_nan(r);
48174 val = JS_NewBigDecimal(ctx, r);
48175 }48420 }
48176 break;48421 break;
48177 default:48422 default:
@@ -48188,10 +48433,12 @@ static JSValue js_bigdecimal_constructor(JSContext *ctx, · 10 unmodified lines
48188{48433{
48189 JSValue val;48434 JSValue val;
48190 if (argc == 0) {48435 if (argc == 0) {
48191 bfdec_t r_s, *r = &r_s;48436 bfdec_t *r;
48192 bfdec_init(ctx->bf_ctx, r);48437 val = JS_NewBigDecimal(ctx);
48438 if (JS_IsException(val))
48439 return val;
48440 r = JS_GetBigDecimal(val);
48193 bfdec_set_zero(r, 0);48441 bfdec_set_zero(r, 0);
48194 val = JS_NewBigDecimal(ctx, r);
48195 } else {48442 } else {
48196 val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);48443 val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
48197 }48444 }
@@ -48230,6 +48477,39 @@ static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val, · 32 unmodified lines
48230 return js_thisBigDecimalValue(ctx, this_val);48477 return js_thisBigDecimalValue(ctx, this_val);
48231}48478}
48232 48479
48480static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
48481{
48482 const char *str;
48483 size_t size;
48484 int rnd_mode;
48485
48486 str = JS_ToCStringLen(ctx, &size, obj);
48487 if (!str)
48488 return -1;
48489 if (strlen(str) != size)
48490 goto invalid_rounding_mode;
48491 if (!strcmp(str, "floor")) {
48492 rnd_mode = BF_RNDD;
48493 } else if (!strcmp(str, "ceiling")) {
48494 rnd_mode = BF_RNDU;
48495 } else if (!strcmp(str, "down")) {
48496 rnd_mode = BF_RNDZ;
48497 } else if (!strcmp(str, "up")) {
48498 rnd_mode = BF_RNDA;
48499 } else if (!strcmp(str, "half-even")) {
48500 rnd_mode = BF_RNDN;
48501 } else if (!strcmp(str, "half-up")) {
48502 rnd_mode = BF_RNDNA;
48503 } else {
48504 invalid_rounding_mode:
48505 JS_FreeCString(ctx, str);
48506 JS_ThrowTypeError(ctx, "invalid rounding mode");
48507 return -1;
48508 }
48509 JS_FreeCString(ctx, str);
48510 return rnd_mode;
48511}
48512
48233typedef struct {48513typedef struct {
48234 int64_t prec;48514 int64_t prec;
48235 bf_flags_t flags;48515 bf_flags_t flags;
@@ -48239,10 +48519,9 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 3 unmodified lines
48239 JSValueConst obj)48519 JSValueConst obj)
48240{48520{
48241 JSValue prop;48521 JSValue prop;
48242 const char *str;
48243 size_t size;
48244 int64_t val;48522 int64_t val;
48245 BOOL has_prec;48523 BOOL has_prec;
48524 int rnd_mode;
48246 48525
48247 if (!JS_IsObject(obj)) {48526 if (!JS_IsObject(obj)) {
48248 JS_ThrowTypeErrorNotAnObject(ctx);48527 JS_ThrowTypeErrorNotAnObject(ctx);
@@ -48251,29 +48530,11 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 2 unmodified lines
48251 prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);48530 prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
48252 if (JS_IsException(prop))48531 if (JS_IsException(prop))
48253 return -1;48532 return -1;
48254 str = JS_ToCStringLen(ctx, &size, prop);48533 rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
48255 JS_FreeValue(ctx, prop);48534 JS_FreeValue(ctx, prop);
48256 if (!str)48535 if (rnd_mode < 0)
48257 return -1;
48258 if (strlen(str) != size)
48259 goto invalid_rounding_mode;
48260 if (!strcmp(str, "floor")) {
48261 fe->flags = BF_RNDD;
48262 } else if (!strcmp(str, "ceiling")) {
48263 fe->flags = BF_RNDU;
48264 } else if (!strcmp(str, "down")) {
48265 fe->flags = BF_RNDZ;
48266 } else if (!strcmp(str, "half-even")) {
48267 fe->flags = BF_RNDN;
48268 } else if (!strcmp(str, "half-up")) {
48269 fe->flags = BF_RNDNA;
48270 } else {
48271 invalid_rounding_mode:
48272 JS_FreeCString(ctx, str);
48273 JS_ThrowTypeError(ctx, "invalid rounding mode");
48274 return -1;48536 return -1;
48275 }48537 fe->flags = rnd_mode;
48276 JS_FreeCString(ctx, str);
48277 48538
48278 prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);48539 prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
48279 if (JS_IsException(prop))48540 if (JS_IsException(prop))
@@ -48282,7 +48543,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 2 unmodified lines
48282 if (!JS_IsUndefined(prop)) {48543 if (!JS_IsUndefined(prop)) {
48283 if (JS_ToInt64SatFree(ctx, &val, prop))48544 if (JS_ToInt64SatFree(ctx, &val, prop))
48284 return -1;48545 return -1;
48285 if (val < 0 || val > BF_PREC_MAX)48546 if (val < 1 || val > BF_PREC_MAX)
48286 goto invalid_precision;48547 goto invalid_precision;
48287 fe->prec = val;48548 fe->prec = val;
48288 has_prec = TRUE;48549 has_prec = TRUE;
@@ -48320,7 +48581,7 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 31 unmodified lines
48320 int argc, JSValueConst *argv, int magic)48581 int argc, JSValueConst *argv, int magic)
48321{48582{
48322 bfdec_t *a, *b, r_s, *r = &r_s;48583 bfdec_t *a, *b, r_s, *r = &r_s;
48323 JSValue op1, op2;48584 JSValue op1, op2, res;
48324 BigDecimalEnv fe_s, *fe = &fe_s;48585 BigDecimalEnv fe_s, *fe = &fe_s;
48325 int op_count, ret;48586 int op_count, ret;
48326 48587
@@ -48354,21 +48615,18 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 27 unmodified lines
48354 fe->flags = BF_RNDZ;48615 fe->flags = BF_RNDZ;
48355 fe->prec = BF_PREC_INF;48616 fe->prec = BF_PREC_INF;
48356 if (op_count < argc) {48617 if (op_count < argc) {
48357 if (js_bigdecimal_get_env(ctx, fe, argv[op_count])) {48618 if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
48358 fail:
48359 JS_FreeValue(ctx, op1);
48360 JS_FreeValue(ctx, op2);
48361 return JS_EXCEPTION;
48362 }
48363 if ((fe->flags & BF_FLAG_RADPNT_PREC) &&
48364 magic != MATH_OP_DIV &&
48365 magic != MATH_OP_ROUND) {
48366 JS_ThrowTypeError(ctx, "maximumFractionDigits is not supported for this operation");
48367 goto fail;48619 goto fail;
48368 }
48369 }48620 }
48370 48621
48371 bfdec_init(ctx->bf_ctx, r);48622 res = JS_NewBigDecimal(ctx);
48623 if (JS_IsException(res)) {
48624 fail:
48625 JS_FreeValue(ctx, op1);
48626 JS_FreeValue(ctx, op2);
48627 return JS_EXCEPTION;
48628 }
48629 r = JS_GetBigDecimal(res);
48372 switch (magic) {48630 switch (magic) {
48373 case MATH_OP_ADD:48631 case MATH_OP_ADD:
48374 ret = bfdec_add(r, a, b, fe->prec, fe->flags);48632 ret = bfdec_add(r, a, b, fe->prec, fe->flags);
@@ -48382,6 +48640,9 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 7 unmodified lines
48382 case MATH_OP_DIV:48640 case MATH_OP_DIV:
48383 ret = bfdec_div(r, a, b, fe->prec, fe->flags);48641 ret = bfdec_div(r, a, b, fe->prec, fe->flags);
48384 break;48642 break;
48643 case MATH_OP_FMOD:
48644 ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
48645 break;
48385 case MATH_OP_SQRT:48646 case MATH_OP_SQRT:
48386 ret = bfdec_sqrt(r, a, fe->prec, fe->flags);48647 ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
48387 break;48648 break;
@@ -48398,16 +48659,119 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
48398 ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |48659 ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
48399 BF_ST_OVERFLOW;48660 BF_ST_OVERFLOW;
48400 if (ret != 0) {48661 if (ret != 0) {
48401 bfdec_delete(r);48662 JS_FreeValue(ctx, res);
48402 return throw_bf_exception(ctx, ret);48663 return throw_bf_exception(ctx, ret);
48403 } else {48664 } else {
48404 return JS_NewBigDecimal(ctx, r);48665 return res;
48666 }
48667}
48668
48669static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
48670 int argc, JSValueConst *argv)
48671{
48672 JSValue val, ret;
48673 int64_t f;
48674 int rnd_mode;
48675
48676 val = js_thisBigDecimalValue(ctx, this_val);
48677 if (JS_IsException(val))
48678 return val;
48679 if (JS_ToInt64Sat(ctx, &f, argv[0]))
48680 goto fail;
48681 if (f < 0 || f > BF_PREC_MAX) {
48682 JS_ThrowRangeError(ctx, "invalid number of digits");
48683 goto fail;
48684 }
48685 rnd_mode = BF_RNDNA;
48686 if (argc > 1) {
48687 rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48688 if (rnd_mode < 0)
48689 goto fail;
48690 }
48691 ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
48692 JS_FreeValue(ctx, val);
48693 return ret;
48694 fail:
48695 JS_FreeValue(ctx, val);
48696 return JS_EXCEPTION;
48697}
48698
48699static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
48700 int argc, JSValueConst *argv)
48701{
48702 JSValue val, ret;
48703 int64_t f;
48704 int rnd_mode;
48705
48706 val = js_thisBigDecimalValue(ctx, this_val);
48707 if (JS_IsException(val))
48708 return val;
48709 if (JS_ToInt64Sat(ctx, &f, argv[0]))
48710 goto fail;
48711 if (JS_IsUndefined(argv[0])) {
48712 ret = js_bigdecimal_to_string1(ctx, val, 0,
48713 BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
48714 } else {
48715 if (f < 0 || f > BF_PREC_MAX) {
48716 JS_ThrowRangeError(ctx, "invalid number of digits");
48717 goto fail;
48718 }
48719 rnd_mode = BF_RNDNA;
48720 if (argc > 1) {
48721 rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48722 if (rnd_mode < 0)
48723 goto fail;
48724 }
48725 ret = js_bigdecimal_to_string1(ctx, val, f + 1,
48726 rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
48727 }
48728 JS_FreeValue(ctx, val);
48729 return ret;
48730 fail:
48731 JS_FreeValue(ctx, val);
48732 return JS_EXCEPTION;
48733}
48734
48735static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
48736 int argc, JSValueConst *argv)
48737{
48738 JSValue val, ret;
48739 int64_t p;
48740 int rnd_mode;
48741
48742 val = js_thisBigDecimalValue(ctx, this_val);
48743 if (JS_IsException(val))
48744 return val;
48745 if (JS_IsUndefined(argv[0])) {
48746 return JS_ToStringFree(ctx, val);
48747 }
48748 if (JS_ToInt64Sat(ctx, &p, argv[0]))
48749 goto fail;
48750 if (p < 1 || p > BF_PREC_MAX) {
48751 JS_ThrowRangeError(ctx, "invalid number of digits");
48752 goto fail;
48753 }
48754 rnd_mode = BF_RNDNA;
48755 if (argc > 1) {
48756 rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48757 if (rnd_mode < 0)
48758 goto fail;
48405 }48759 }
48760 ret = js_bigdecimal_to_string1(ctx, val, p,
48761 rnd_mode | BF_FTOA_FORMAT_FIXED);
48762 JS_FreeValue(ctx, val);
48763 return ret;
48764 fail:
48765 JS_FreeValue(ctx, val);
48766 return JS_EXCEPTION;
48406}48767}
48407 48768
48408static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {48769static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
48409 JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),48770 JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
48410 JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),48771 JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
48772 JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
48773 JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
48774 JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
48411};48775};
48412 48776
48413static const JSCFunctionListEntry js_bigdecimal_funcs[] = {48777static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
@@ -48415,6 +48779,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = { · 1 unmodified line
48415 JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),48779 JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
48416 JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),48780 JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
48417 JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),48781 JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
48782 JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
48418 JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),48783 JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
48419 JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),48784 JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
48420};48785};
@@ -49512,6 +49877,8 @@ static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val, · 1091 unmodified lines
49512 count = min_int(final - from, len - to);49877 count = min_int(final - from, len - to);
49513 if (count > 0) {49878 if (count > 0) {
49514 p = JS_VALUE_GET_OBJ(this_val);49879 p = JS_VALUE_GET_OBJ(this_val);
49880 if (typed_array_is_detached(ctx, p))
49881 return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
49515 shift = typed_array_size_log2(p->class_id);49882 shift = typed_array_size_log2(p->class_id);
49516 memmove(p->u.array.u.uint8_ptr + (to << shift),49883 memmove(p->u.array.u.uint8_ptr + (to << shift),
49517 p->u.array.u.uint8_ptr + (from << shift),49884 p->u.array.u.uint8_ptr + (from << shift),
@@ -49579,6 +49946,9 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, · 61 unmodified lines
49579 return JS_EXCEPTION;49946 return JS_EXCEPTION;
49580 }49947 }
49581 49948
49949 if (typed_array_is_detached(ctx, p))
49950 return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
49951
49582 shift = typed_array_size_log2(p->class_id);49952 shift = typed_array_size_log2(p->class_id);
49583 switch(shift) {49953 switch(shift) {
49584 case 0:49954 case 0:
quickjs.h+11−5
@@ -53,7 +53,7 @@ typedef struct JSClass JSClass; · 52 unmodified lines
53typedef uint32_t JSClassID;53typedef uint32_t JSClassID;
54typedef uint32_t JSAtom;54typedef uint32_t JSAtom;
55 55
56#if defined(__x86_64__) || defined(__aarch64__)56#if INTPTR_MAX >= INT64_MAX
57#define JS_PTR6457#define JS_PTR64
58#define JS_PTR64_DEF(a) a58#define JS_PTR64_DEF(a) a
59#else59#else
@@ -366,7 +366,9 @@ void JS_AddIntrinsicPromise(JSContext *ctx); · 306 unmodified lines
366void JS_AddIntrinsicBigInt(JSContext *ctx);366void JS_AddIntrinsicBigInt(JSContext *ctx);
367void JS_AddIntrinsicBigFloat(JSContext *ctx);367void JS_AddIntrinsicBigFloat(JSContext *ctx);
368void JS_AddIntrinsicBigDecimal(JSContext *ctx);368void JS_AddIntrinsicBigDecimal(JSContext *ctx);
369/* enable "use bigint", "use math" and operator overloading */369/* enable operator overloading */
370void JS_AddIntrinsicOperators(JSContext *ctx);
371/* enable "use math" */
370void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);372void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
371 373
372JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,374JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
@@ -531,12 +533,16 @@ static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) · 158 unmodified lines
531 return v;533 return v;
532}534}
533 535
534JS_BOOL JS_IsNumber(JSValueConst v);536static inline JS_BOOL JS_IsNumber(JSValueConst v)
537{
538 int tag = JS_VALUE_GET_TAG(v);
539 return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
540}
535 541
536static inline JS_BOOL JS_IsInteger(JSValueConst v)542static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
537{543{
538 int tag = JS_VALUE_GET_TAG(v);544 int tag = JS_VALUE_GET_TAG(v);
539 return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT;545 return tag == JS_TAG_BIG_INT;
540}546}
541 547
542static inline JS_BOOL JS_IsBigFloat(JSValueConst v)548static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
repl.js+6−28
@@ -1,8 +1,8 @@
1/*1/*
2 * QuickJS Read Eval Print Loop2 * QuickJS Read Eval Print Loop
3 * 3 *
4 * Copyright (c) 2017-2019 Fabrice Bellard4 * Copyright (c) 2017-2020 Fabrice Bellard
5 * Copyright (c) 2017-2019 Charlie Gordon5 * Copyright (c) 2017-2020 Charlie Gordon
6 *6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal8 * of this software and associated documentation files (the "Software"), to deal
@@ -860,18 +860,6 @@ import * as os from "os"; · 851 unmodified lines
860 var hex_mode = false;860 var hex_mode = false;
861 var eval_mode = "std";861 var eval_mode = "std";
862 862
863 function bignum_typeof(a) {
864 "use bigint";
865 return typeof a;
866 }
867
868 function eval_mode_typeof(a) {
869 if (eval_mode === "std")
870 return typeof a;
871 else
872 return bignum_typeof(a);
873 }
874
875 function number_to_string(a, radix) {863 function number_to_string(a, radix) {
876 var s;864 var s;
877 if (!isFinite(a)) {865 if (!isFinite(a)) {
@@ -897,13 +885,6 @@ import * as os from "os"; · 19 unmodified lines
897 s = a.toString();885 s = a.toString();
898 }886 }
899 }887 }
900 if (eval_mode !== "std" && s.indexOf(".") < 0 &&
901 ((radix == 16 && s.indexOf("p") < 0) ||
902 (radix == 10 && s.indexOf("e") < 0))) {
903 /* add a decimal point so that the floating point type
904 is visible */
905 s += ".0";
906 }
907 return s;888 return s;
908 }889 }
909 }890 }
@@ -975,7 +956,7 @@ import * as os from "os"; · 65 unmodified lines
975 function print_rec(a) {956 function print_rec(a) {
976 var n, i, keys, key, type, s;957 var n, i, keys, key, type, s;
977 958
978 type = eval_mode_typeof(a);959 type = typeof(a);
979 if (type === "object") {960 if (type === "object") {
980 if (a === null) {961 if (a === null) {
981 std.puts(a);962 std.puts(a);
@@ -1037,7 +1018,7 @@ import * as os from "os"; · 55 unmodified lines
1037 } else if (type === "bigfloat") {1018 } else if (type === "bigfloat") {
1038 std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));1019 std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
1039 } else if (type === "bigdecimal") {1020 } else if (type === "bigdecimal") {
1040 std.puts(a.toString() + "d");1021 std.puts(a.toString() + "m");
1041 } else if (type === "symbol") {1022 } else if (type === "symbol") {
1042 std.puts(String(a));1023 std.puts(String(a));
1043 } else if (type === "function") {1024 } else if (type === "function") {
@@ -1133,8 +1114,7 @@ import * as os from "os"; · 89 unmodified lines
1133 param = expr.substring(cmd.length + 1).trim();1114 param = expr.substring(cmd.length + 1).trim();
1134 if (param === "") {1115 if (param === "") {
1135 std.puts("Running mode=" + eval_mode + "\n");1116 std.puts("Running mode=" + eval_mode + "\n");
1136 } else if (param === "std" || param === "math" ||1117 } else if (param === "std" || param === "math") {
1137 param === "bigint") {
1138 eval_mode = param;1118 eval_mode = param;
1139 } else {1119 } else {
1140 std.puts("Invalid mode\n");1120 std.puts("Invalid mode\n");
@@ -1192,7 +1172,7 @@ import * as os from "os"; · 51 unmodified lines
1192 std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +1172 std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
1193 "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");1173 "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
1194 if (!has_jscalc) {1174 if (!has_jscalc) {
1195 std.puts("\\mode [std|bigint|math] change the running mode (current = " + eval_mode + ")\n");1175 std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
1196 }1176 }
1197 }1177 }
1198 if (!config_numcalc) {1178 if (!config_numcalc) {
@@ -1206,8 +1186,6 @@ import * as os from "os"; · 7 unmodified lines
1206 try {1186 try {
1207 if (eval_mode === "math")1187 if (eval_mode === "math")
1208 expr = '"use math"; void 0;' + expr;1188 expr = '"use math"; void 0;' + expr;
1209 else if (eval_mode === "bigint")
1210 expr = '"use bigint"; void 0;' + expr;
1211 var now = (new Date).getTime();1189 var now = (new Date).getTime();
1212 /* eval as a script */1190 /* eval as a script */
1213 result = std.evalScript(expr, { backtrace_barrier: true });1191 result = std.evalScript(expr, { backtrace_barrier: true });
test262_errors.txt+13−0
@@ -1,4 +1,17 @@
1test262/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
2test262/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
3test262/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
4test262/test/language/expressions/class/super-evaluation-order.js:26: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
5test262/test/language/expressions/class/super-evaluation-order.js:26: strict mode: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
1test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called6test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
2test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called7test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
8test262/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
9test262/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
10test262/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
11test262/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
12test262/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
3test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property13test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property
4test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property14test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
15test262/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
16test262/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
17test262/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
tests/test_bignum.js+125−40
@@ -171,67 +171,152 @@ function test_bigfloat() · 170 unmodified lines
171 e = new BigFloatEnv(128);171 e = new BigFloatEnv(128);
172 assert(e.prec == 128);172 assert(e.prec == 128);
173 a = BigFloat.sqrt(2l, e);173 a = BigFloat.sqrt(2l, e);
174 assert(a == BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));174 assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
175 assert(e.inexact === true);175 assert(e.inexact === true);
176 assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);176 assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
177 177
178 b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);178 b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
179 assert(a == b);179 assert(a === b);
180
181 assert(BigFloat.isNaN(BigFloat(NaN)));
182 assert(BigFloat.isFinite(1l));
183 assert(!BigFloat.isFinite(1l/0l));
184
185 assert(BigFloat.abs(-3l) === 3l);
186 assert(BigFloat.sign(-3l) === -1l);
187
188 assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
189 assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
190 assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
191
192 assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
193 assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
194 assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
195
196 assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
197 assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
198 assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
199 assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
200
201 assert(BigFloat.floor(2.5l) === 2l);
202 assert(BigFloat.ceil(2.5l) === 3l);
203 assert(BigFloat.trunc(-2.5l) === -2l);
204 assert(BigFloat.round(2.5l) === 3l);
205
206 assert(BigFloat.fmod(3l,2l) === 1l);
207 assert(BigFloat.remainder(3l,2l) === -1l);
208
209 /* string conversion */
210 assert((1234.125l).toString(), "1234.125");
211 assert((1234.125l).toFixed(2), "1234.13");
212 assert((1234.125l).toFixed(2, "down"), "1234.12");
213 assert((1234.125l).toExponential(), "1.234125e+3");
214 assert((1234.125l).toExponential(5), "1.23413e+3");
215 assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
216 assert((1234.125l).toPrecision(6), "1234.13");
217 assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
218
219 /* string conversion with binary base */
220 assert((0x123.438l).toString(16), "123.438");
221 assert((0x323.438l).toString(16), "323.438");
222 assert((0x723.438l).toString(16), "723.438");
223 assert((0xf23.438l).toString(16), "f23.438");
224 assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
225 assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
226 assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
227 assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
228 assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
229 assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
230 assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
231 assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
232 assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
233 assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
234 assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
235 assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
180}236}
181 237
182function test_bigdecimal()238function test_bigdecimal()
183{239{
184 assert(1d === 1d);240 assert(1m === 1m);
185 assert(1d !== 2d);241 assert(1m !== 2m);
186 test_less(1d, 2d);242 test_less(1m, 2m);
187 test_eq(2d, 2d);243 test_eq(2m, 2m);
188 244
189 test_less(1, 2d);245 test_less(1, 2m);
190 test_eq(2, 2d);246 test_eq(2, 2m);
191 247
192 test_less(1.1, 2d);248 test_less(1.1, 2m);
193 test_eq(Math.sqrt(4), 2d);249 test_eq(Math.sqrt(4), 2m);
194 250
195 test_less(2n, 3d);251 test_less(2n, 3m);
196 test_eq(3n, 3d);252 test_eq(3n, 3m);
197 253
198 assert(BigDecimal("1234.1") === 1234.1d);254 assert(BigDecimal("1234.1") === 1234.1m);
199 assert(BigDecimal(" 1234.1") === 1234.1d);255 assert(BigDecimal(" 1234.1") === 1234.1m);
200 assert(BigDecimal(" 1234.1 ") === 1234.1d);256 assert(BigDecimal(" 1234.1 ") === 1234.1m);
201
202 assert(BigDecimal(0.1) === 0.1d);
203 assert(BigDecimal(123) === 123d);
204 assert(BigDecimal(true) === 1d);
205 257
206 assert(123d + 1d === 124d);258 assert(BigDecimal(0.1) === 0.1m);
207 assert(123d - 1d === 122d);259 assert(BigDecimal(123) === 123m);
260 assert(BigDecimal(true) === 1m);
208 261
209 assert(3.2d * 3d === 9.6d);262 assert(123m + 1m === 124m);
210 assert(10d / 2d === 5d);263 assert(123m - 1m === 122m);
211 assertThrows(RangeError, () => { 10d / 3d } );
212 assert(BigDecimal.div(20d, 3d,
213 { roundingMode: "half-even",
214 maximumSignificantDigits: 3 }) === 6.67d);
215 assert(BigDecimal.div(20d, 3d,
216 { roundingMode: "half-even",
217 maximumFractionDigits: 3 }) === 6.667d);
218 264
219 assert(10d % 3d === 1d);265 assert(3.2m * 3m === 9.6m);
220 assert(-10d % 3d === -1d);266 assert(10m / 2m === 5m);
267 assertThrows(RangeError, () => { 10m / 3m } );
221 268
222 assert(-10d % 3d === -1d);269 assert(10m % 3m === 1m);
270 assert(-10m % 3m === -1m);
223 271
224 assert(1234.5d ** 3d === 1881365963.625d);272 assert(1234.5m ** 3m === 1881365963.625m);
225 assertThrows(RangeError, () => { 2d ** 3.1d } );273 assertThrows(RangeError, () => { 2m ** 3.1m } );
226 assertThrows(RangeError, () => { 2d ** -3d } );274 assertThrows(RangeError, () => { 2m ** -3m } );
227 275
228 assert(BigDecimal.sqrt(2d,276 assert(BigDecimal.sqrt(2m,
277 { roundingMode: "half-even",
278 maximumSignificantDigits: 4 }) === 1.414m);
279 assert(BigDecimal.sqrt(101m,
229 { roundingMode: "half-even",280 { roundingMode: "half-even",
230 maximumSignificantDigits: 4 }) === 1.414d);281 maximumFractionDigits: 3 }) === 10.050m);
282 assert(BigDecimal.sqrt(0.002m,
283 { roundingMode: "half-even",
284 maximumFractionDigits: 3 }) === 0.045m);
231 285
232 assert(BigDecimal.round(3.14159d,286 assert(BigDecimal.round(3.14159m,
287 { roundingMode: "half-even",
288 maximumFractionDigits: 3 }) === 3.142m);
289
290 assert(BigDecimal.add(3.14159m, 0.31212m,
291 { roundingMode: "half-even",
292 maximumFractionDigits: 2 }) === 3.45m);
293 assert(BigDecimal.sub(3.14159m, 0.31212m,
294 { roundingMode: "down",
295 maximumFractionDigits: 2 }) === 2.82m);
296 assert(BigDecimal.mul(3.14159m, 0.31212m,
297 { roundingMode: "half-even",
298 maximumFractionDigits: 3 }) === 0.981m);
299 assert(BigDecimal.mod(3.14159m, 0.31211m,
300 { roundingMode: "half-even",
301 maximumFractionDigits: 4 }) === 0.0205m);
302 assert(BigDecimal.div(20m, 3m,
303 { roundingMode: "half-even",
304 maximumSignificantDigits: 3 }) === 6.67m);
305 assert(BigDecimal.div(20m, 3m,
233 { roundingMode: "half-even",306 { roundingMode: "half-even",
234 maximumFractionDigits: 3 }) === 3.142d);307 maximumFractionDigits: 50 }) ===
308 6.66666666666666666666666666666666666666666666666667m);
309
310 /* string conversion */
311 assert((1234.125m).toString(), "1234.125");
312 assert((1234.125m).toFixed(2), "1234.13");
313 assert((1234.125m).toFixed(2, "down"), "1234.12");
314 assert((1234.125m).toExponential(), "1.234125e+3");
315 assert((1234.125m).toExponential(5), "1.23413e+3");
316 assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
317 assert((1234.125m).toPrecision(6), "1234.13");
318 assert((1234.125m).toPrecision(6, "down"), "1234.12");
319 assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
235}320}
236 321
237test_bigint1();322test_bigint1();
tests/test_op_overloading.js+207−0
@@ -0,0 +1,207 @@
1"use strict";
2
3function assert(actual, expected, message) {
4 if (arguments.length == 1)
5 expected = true;
6
7 if (actual === expected)
8 return;
9
10 if (actual !== null && expected !== null
11 && typeof actual == 'object' && typeof expected == 'object'
12 && actual.toString() === expected.toString())
13 return;
14
15 throw Error("assertion failed: got |" + actual + "|" +
16 ", expected |" + expected + "|" +
17 (message ? " (" + message + ")" : ""));
18}
19
20/* operators overloading with Operators.create() */
21function test_operators_create() {
22 class Vec2
23 {
24 constructor(x, y) {
25 this.x = x;
26 this.y = y;
27 }
28 static mul_scalar(p1, a) {
29 var r = new Vec2();
30 r.x = p1.x * a;
31 r.y = p1.y * a;
32 return r;
33 }
34 toString() {
35 return "Vec2(" + this.x + "," + this.y + ")";
36 }
37 }
38
39 Vec2.prototype[Symbol.operatorSet] = Operators.create(
40 {
41 "+"(p1, p2) {
42 var r = new Vec2();
43 r.x = p1.x + p2.x;
44 r.y = p1.y + p2.y;
45 return r;
46 },
47 "-"(p1, p2) {
48 var r = new Vec2();
49 r.x = p1.x - p2.x;
50 r.y = p1.y - p2.y;
51 return r;
52 },
53 "=="(a, b) {
54 return a.x == b.x && a.y == b.y;
55 },
56 "<"(a, b) {
57 var r;
58 /* lexicographic order */
59 if (a.x == b.x)
60 r = (a.y < b.y);
61 else
62 r = (a.x < b.x);
63 return r;
64 },
65 "++"(a) {
66 var r = new Vec2();
67 r.x = a.x + 1;
68 r.y = a.y + 1;
69 return r;
70 }
71 },
72 {
73 left: Number,
74 "*"(a, b) {
75 return Vec2.mul_scalar(b, a);
76 }
77 },
78 {
79 right: Number,
80 "*"(a, b) {
81 return Vec2.mul_scalar(a, b);
82 }
83 });
84
85 var a = new Vec2(1, 2);
86 var b = new Vec2(3, 4);
87 var r;
88
89 r = a * 2 + 3 * b;
90 assert(r.x === 11 && r.y === 16);
91 assert(a == a, true);
92 assert(a == b, false);
93 assert(a != a, false);
94 assert(a < b, true);
95 assert(a <= b, true);
96 assert(b < a, false);
97 assert(b <= a, false);
98 assert(a <= a, true);
99 assert(a >= a, true);
100 a++;
101 assert(a.x === 2 && a.y === 3);
102 r = ++a;
103 assert(a.x === 3 && a.y === 4);
104 assert(r === a);
105}
106
107/* operators overloading thru inheritance */
108function test_operators()
109{
110 var Vec2;
111
112 function mul_scalar(p1, a) {
113 var r = new Vec2();
114 r.x = p1.x * a;
115 r.y = p1.y * a;
116 return r;
117 }
118
119 var vec2_ops = Operators({
120 "+"(p1, p2) {
121 var r = new Vec2();
122 r.x = p1.x + p2.x;
123 r.y = p1.y + p2.y;
124 return r;
125 },
126 "-"(p1, p2) {
127 var r = new Vec2();
128 r.x = p1.x - p2.x;
129 r.y = p1.y - p2.y;
130 return r;
131 },
132 "=="(a, b) {
133 return a.x == b.x && a.y == b.y;
134 },
135 "<"(a, b) {
136 var r;
137 /* lexicographic order */
138 if (a.x == b.x)
139 r = (a.y < b.y);
140 else
141 r = (a.x < b.x);
142 return r;
143 },
144 "++"(a) {
145 var r = new Vec2();
146 r.x = a.x + 1;
147 r.y = a.y + 1;
148 return r;
149 }
150 },
151 {
152 left: Number,
153 "*"(a, b) {
154 return mul_scalar(b, a);
155 }
156 },
157 {
158 right: Number,
159 "*"(a, b) {
160 return mul_scalar(a, b);
161 }
162 });
163
164 Vec2 = class Vec2 extends vec2_ops
165 {
166 constructor(x, y) {
167 super();
168 this.x = x;
169 this.y = y;
170 }
171 toString() {
172 return "Vec2(" + this.x + "," + this.y + ")";
173 }
174 }
175
176 var a = new Vec2(1, 2);
177 var b = new Vec2(3, 4);
178 var r;
179
180 r = a * 2 + 3 * b;
181 assert(r.x === 11 && r.y === 16);
182 assert(a == a, true);
183 assert(a == b, false);
184 assert(a != a, false);
185 assert(a < b, true);
186 assert(a <= b, true);
187 assert(b < a, false);
188 assert(b <= a, false);
189 assert(a <= a, true);
190 assert(a >= a, true);
191 a++;
192 assert(a.x === 2 && a.y === 3);
193 r = ++a;
194 assert(a.x === 3 && a.y === 4);
195 assert(r === a);
196}
197
198function test_default_op()
199{
200 assert(Object(1) + 2, 3);
201 assert(Object(1) + true, 2);
202 assert(-Object(1), -1);
203}
204
205test_operators_create();
206test_operators();
207test_default_op();
tests/test_qjscalc.js+15−3
@@ -66,13 +66,14 @@ function test_integer() · 65 unmodified lines
66 66
67 r = (1 << 31) < 0;67 r = (1 << 31) < 0;
68 assert(r, false, "(1 << 31) < 0 === false");68 assert(r, false, "(1 << 31) < 0 === false");
69
70 assert(typeof 1 === "number");
71 assert(typeof 9007199254740991 === "number");
72 assert(typeof 9007199254740992 === "bigint");
69}73}
70 74
71function test_float()75function test_float()
72{76{
73 var e, a, b, sqrt2;
74
75 assert(typeof 1 === "bigint");
76 assert(typeof 1.0 === "bigfloat");77 assert(typeof 1.0 === "bigfloat");
77 assert(1 == 1.0);78 assert(1 == 1.0);
78 assert(1 !== 1.0);79 assert(1 !== 1.0);
@@ -101,6 +102,16 @@ function test_modulo() · 22 unmodified lines
101 assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);102 assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
102}103}
103 104
105function test_fraction()
106{
107 assert((1/3 + 1).toString(), "4/3")
108 assert((2/3)^30, 1073741824/205891132094649);
109 assert(1/3 < 2/3);
110 assert(1/3 < 1);
111 assert(1/3 == 1.0/3);
112 assert(1.0/3 < 2/3);
113}
114
104function test_mod()115function test_mod()
105{116{
106 var a, b, p;117 var a, b, p;
@@ -235,6 +246,7 @@ test_integer(); · 128 unmodified lines
235test_float();246test_float();
236 247
237test_modulo();248test_modulo();
249test_fraction();
238test_mod();250test_mod();
239test_polynomial();251test_polynomial();
240test_poly_mod();252test_poly_mod();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t