Unified · Split
| @@ -1,3 +1,15 @@ | |||
| 1 | 2020-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 | |||
| 1 | 2020-01-05: | 13 | 2020-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. |
| @@ -1,8 +1,8 @@ | |||
| 1 | # | 1 | # |
| 2 | # QuickJS Javascript Engine | 2 | # QuickJS Javascript Engine |
| 3 | # | 3 | # |
| 4 | # Copyright (c) 2017-2019 Fabrice Bellard | 4 | # Copyright (c) 2017-2020 Fabrice Bellard |
| 5 | # Copyright (c) 2017-2019 Charlie Gordon | 5 | # Copyright (c) 2017-2020 Charlie Gordon |
| 6 | # | 6 | # |
| 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy | 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | # of this software and associated documentation files (the "Software"), to deal | 8 | # of this software and associated documentation files (the "Software"), to deal |
| @@ -47,6 +47,8 @@ prefix=/usr/local · 38 unmodified lines | |||
| 47 | #CONFIG_PROFILE=y | 47 | #CONFIG_PROFILE=y |
| 48 | # use address sanitizer | 48 | # use address sanitizer |
| 49 | #CONFIG_ASAN=y | 49 | #CONFIG_ASAN=y |
| 50 | # include the code for BigInt/BigFloat/BigDecimal and math mode | ||
| 51 | CONFIG_BIGNUM=y | ||
| 50 | 52 | ||
| 51 | OBJDIR=.obj | 53 | OBJDIR=.obj |
| 52 | 54 | ||
| @@ -94,6 +96,9 @@ ifdef CONFIG_WERROR · 41 unmodified lines | |||
| 94 | CFLAGS+=-Werror | 96 | CFLAGS+=-Werror |
| 95 | endif | 97 | endif |
| 96 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" | 98 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" |
| 99 | ifdef CONFIG_BIGNUM | ||
| 100 | DEFINES+=-DCONFIG_BIGNUM | ||
| 101 | endif | ||
| 97 | CFLAGS+=$(DEFINES) | 102 | CFLAGS+=$(DEFINES) |
| 98 | CFLAGS_DEBUG=$(CFLAGS) -O0 | 103 | CFLAGS_DEBUG=$(CFLAGS) -O0 |
| 99 | CFLAGS_SMALL=$(CFLAGS) -Os | 104 | CFLAGS_SMALL=$(CFLAGS) -Os |
| @@ -153,9 +158,13 @@ endif · 53 unmodified lines | |||
| 153 | 158 | ||
| 154 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) | 159 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) |
| 155 | 160 | ||
| 156 | QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/libbf.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o | 161 | QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o |
| 157 | 162 | ||
| 158 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(OBJDIR)/qjscalc.o $(QJS_LIB_OBJS) | 163 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) |
| 164 | ifdef CONFIG_BIGNUM | ||
| 165 | QJS_LIB_OBJS+=$(OBJDIR)/libbf.o | ||
| 166 | QJS_OBJS+=$(OBJDIR)/qjscalc.o | ||
| 167 | endif | ||
| 159 | 168 | ||
| 160 | LIBS=-lm | 169 | LIBS=-lm |
| 161 | ifndef CONFIG_WIN32 | 170 | ifndef CONFIG_WIN32 |
| @@ -215,7 +224,7 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) · 53 unmodified lines | |||
| 215 | $(AR) rcs $@ $^ | 224 | $(AR) rcs $@ $^ |
| 216 | endif # CONFIG_LTO | 225 | endif # CONFIG_LTO |
| 217 | 226 | ||
| 218 | repl.c: $(QJSC) repl.js | 227 | repl.c: $(QJSC) repl.js |
| 219 | $(QJSC) -c -o $@ -m repl.js | 228 | $(QJSC) -c -o $@ -m repl.js |
| 220 | 229 | ||
| 221 | qjscalc.c: $(QJSC) qjscalc.js | 230 | qjscalc.c: $(QJSC) qjscalc.js |
| @@ -301,7 +310,10 @@ endif · 79 unmodified lines | |||
| 301 | HELLO_SRCS=examples/hello.js | 310 | HELLO_SRCS=examples/hello.js |
| 302 | HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ | 311 | HELLO_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-bigint | 313 | -fno-date -fno-module-loader |
| 314 | ifdef CONFIG_BIGNUM | ||
| 315 | HELLO_OPTS+=-fno-bigint | ||
| 316 | endif | ||
| 305 | 317 | ||
| 306 | hello.c: $(QJSC) $(HELLO_SRCS) | 318 | hello.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.js | 384 | ./qjs tests/test_loop.js |
| 373 | ./qjs tests/test_std.js | 385 | ./qjs tests/test_std.js |
| 374 | ifndef CONFIG_DARWIN | 386 | ifndef CONFIG_DARWIN |
| 387 | ifdef CONFIG_BIGNUM | ||
| 375 | ./qjs --bignum tests/test_bjson.js | 388 | ./qjs --bignum tests/test_bjson.js |
| 389 | else | ||
| 390 | ./qjs tests/test_bjson.js | ||
| 391 | endif | ||
| 376 | ./qjs examples/test_point.js | 392 | ./qjs examples/test_point.js |
| 377 | endif | 393 | endif |
| 394 | ifdef CONFIG_BIGNUM | ||
| 395 | ./qjs --bignum tests/test_op_overloading.js | ||
| 378 | ./qjs --bignum tests/test_bignum.js | 396 | ./qjs --bignum tests/test_bignum.js |
| 379 | ./qjs --qjscalc tests/test_qjscalc.js | 397 | ./qjs --qjscalc tests/test_qjscalc.js |
| 398 | endif | ||
| 380 | ifdef CONFIG_M32 | 399 | ifdef CONFIG_M32 |
| 381 | ./qjs32 tests/test_closure.js | 400 | ./qjs32 tests/test_closure.js |
| 382 | ./qjs32 tests/test_op.js | 401 | ./qjs32 tests/test_op.js |
| 383 | ./qjs32 tests/test_builtin.js | 402 | ./qjs32 tests/test_builtin.js |
| 384 | ./qjs32 tests/test_loop.js | 403 | ./qjs32 tests/test_loop.js |
| 385 | ./qjs32 tests/test_std.js | 404 | ./qjs32 tests/test_std.js |
| 405 | ifdef CONFIG_BIGNUM | ||
| 406 | ./qjs32 --bignum tests/test_op_overloading.js | ||
| 386 | ./qjs32 --bignum tests/test_bignum.js | 407 | ./qjs32 --bignum tests/test_bignum.js |
| 387 | ./qjs32 --qjscalc tests/test_qjscalc.js | 408 | ./qjs32 --qjscalc tests/test_qjscalc.js |
| 388 | endif | 409 | endif |
| 410 | endif | ||
| 389 | 411 | ||
| 390 | stats: qjs qjs32 | 412 | stats: qjs qjs32 |
| 391 | ./qjs -qd | 413 | ./qjs -qd |
| @@ -73,6 +73,5 @@ REPL: · 72 unmodified lines | |||
| 73 | Test262o: 0/11262 errors, 463 excluded | 73 | Test262o: 0/11262 errors, 463 excluded |
| 74 | Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) | 74 | Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) |
| 75 | 75 | ||
| 76 | Test262: 4/67619 errors, 913 excluded, 1660 skipped | 76 | Test262: 17/69942 errors, 855 excluded, 581 skipped |
| 77 | Test262bn: 4/69722 errors, 846 excluded, 672 skipped | 77 | test262 commit: 28b4fcca4b1b1d278dfe0cc0e69c7d9d59b31aab |
| 78 | test262 commit: 19fd4bea797646ae9bbfc9d325f14052ca370b54 | ||
| @@ -1 +1 @@ | |||
| 1 | 2020-01-05 | 1 | 2020-01-19 |
| @@ -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 | |||
| 119 | language while being 100% backward compatible: | 91 | language while being 100% backward compatible: |
| 120 | </p> | 92 | </p> |
| 121 | <ul> | 93 | <ul> |
| 122 | <li> Overloading of the standard operators | 94 | <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>. |
| 123 | to 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 | ||
| 102 | remainder. <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> |
| 134 | mode which relies on the bigint mode and the operator overloading. | 108 | mode 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 | 115 | implements 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 custom | 116 | looking at the <code>Symbol.operatorSet</code> property in the objects. The |
| 143 | operator method is searched before doing the legacy Javascript | 117 | changes 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 | ||
| 147 | and 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 | ||
| 176 | is looked up in the constructor. | ||
| 177 | |||
| 178 | </li><li> Otherwise, the property <code>Symbol.operatorOrder</code> is looked up in both | ||
| 179 | constructors and converted to <code>Int32</code>. The operator is then | ||
| 180 | looked in the constructor with the larger <code>Symbol.operatorOrder</code> | ||
| 181 | value. 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>&</code></dt> | ||
| 226 | <dd><p><code>Symbol.operatorAnd</code> | ||
| 227 | </p> | ||
| 228 | </dd> | ||
| 229 | <dt><code><<</code></dt> | ||
| 230 | <dd><p><code>Symbol.operatorShl</code> | ||
| 231 | </p> | ||
| 232 | </dd> | ||
| 233 | <dt><code>>></code></dt> | ||
| 234 | <dd><p><code>Symbol.operatorShr</code> | ||
| 235 | </p> | ||
| 236 | </dd> | ||
| 237 | <dt><code><</code></dt> | ||
| 238 | <dd><p><code>Symbol.operatorCmpLT</code> | ||
| 239 | </p> | ||
| 240 | </dd> | ||
| 241 | <dt><code>></code></dt> | ||
| 242 | <dd><p><code>Symbol.operatorCmpLT</code>, operands swapped | ||
| 243 | </p> | ||
| 244 | </dd> | ||
| 245 | <dt><code><=</code></dt> | ||
| 246 | <dd><p><code>Symbol.operatorCmpLE</code> | ||
| 247 | </p> | ||
| 248 | </dd> | ||
| 249 | <dt><code>>=</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>"use bigint"</code> directive. It | ||
| 300 | propagates the same way as the strict mode. In bigint mode, all | ||
| 301 | integers are considered as <code>bigint</code> (arbitrarily large integer, | ||
| 302 | similar to the TC39 BigInt | ||
| 303 | proposal<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>) | ||
| 304 | instead of <code>number</code> (floating point number). In order to be able | ||
| 305 | to exchange data between standard and bigint modes, numbers are | ||
| 306 | internally 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 | ||
| 318 | when it returns a <code>number</code>, it is either of SmallInt or | ||
| 319 | Float. But the difference between SmallInt and Float is not observable | ||
| 320 | in standard mode. | ||
| 321 | </p> | ||
| 322 | <p>In bigint mode, each operation behaves differently whether its | ||
| 323 | operands are integer or float. The difference between SmallInt and | ||
| 324 | BigInt 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 === "number"</code> and <code>typeof 1 === "bigint"</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 << 32 === 4294967296</code> while it gives <code>1</code> in standard mode. However, the <code>>>></code> operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>. | ||
| 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>"integer"</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 | ||
| 374 | Javascript. Then the general case is that an Integer is returned if | ||
| 375 | both operands are Integer. Otherwise, a float is returned. | ||
| 376 | </p> | ||
| 377 | <p>The <code>+</code> operator also accepts strings as input and behaves like | ||
| 378 | standard Javascript in this case. | ||
| 379 | </p> | ||
| 380 | <p>The binary operator <code>%</code> returns the truncated remainder of the | ||
| 381 | division. When the result is an Integer type, a dividend of zero yields a | ||
| 382 | RangeError exception. | ||
| 383 | </p> | ||
| 384 | <p>The binary operator <code>%</code> in math mode returns the Euclidian | ||
| 385 | remainder 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 | ||
| 390 | the operands is float. Otherwise, <code>BigInt[Symbol.operatorDiv]</code> is | ||
| 391 | invoked. | ||
| 392 | </p> | ||
| 393 | <p>The returned type of <code>a ** b</code> is Float if <em>a</em> or <em>b</em> | ||
| 394 | are Float. If <em>a</em> and <em>b</em> are integers: | ||
| 395 | </p><ul> | ||
| 396 | <li> <em>b < 0</em> returns a Float in bigint mode. In math mode, <code>BigInt[Symbol.operatorPow]</code> is invoked. | ||
| 397 | |||
| 398 | </li><li> <em>b >= 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 | ||
| 402 | operand. They performs no floating point rounding when the result is a | ||
| 403 | float. | ||
| 404 | </p> | ||
| 405 | <p>The unary operators <code>++</code> and <code>--</code> return the same type as | ||
| 406 | their operand. | ||
| 407 | </p> | ||
| 408 | <p>In standard mode: | ||
| 409 | </p> | ||
| 410 | <p>If the operator returns an Integer and that the result fits a | ||
| 411 | SmallInt, it is converted to SmallInt. Otherwise, the Integer is | ||
| 412 | converted 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 | ||
| 417 | SmallInt, 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 | ||
| 425 | SmallInt 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 | ||
| 430 | values are converted to integer by rounding them to zero. | ||
| 431 | </p> | ||
| 432 | <p>The logical operators are defined assuming the integers are | ||
| 433 | represented in two complement notation. | ||
| 434 | </p> | ||
| 435 | <p>For <code><<</code> and <code><<</code>, the shift can be positive or negative. So | ||
| 436 | <code>a << b</code> is defined as <em>\lfloor a/2^{-b} \rfloor</em> and | ||
| 437 | <code>a >> b</code> is defined as <em>\lfloor a/2^{b} \rfloor</em>. | ||
| 438 | </p> | ||
| 439 | <p>The operator <code>>>></code> is supported for backward compatibility and | ||
| 440 | behaves 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 | ||
| 443 | it 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 <, <=, >, >=, ==, != work as expected with | ||
| 449 | integers 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 | ||
| 452 | semantics. 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 than | 137 | <p>A few properties are added to the BigInt object: |
| 459 | in standard Javascript: | ||
| 460 | </p> | ||
| 461 | <ol> | ||
| 462 | <li> A number literal without a decimal point or an exponent is considered | ||
| 463 | as an Integer. Otherwise it is a Float. | ||
| 464 | |||
| 465 | </li><li> Hexadecimal, octal or binary floating point literals are accepted with | ||
| 466 | a 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 | ||
| 468 | C99. 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 | ||
| 479 | invoked as a function, it converts its first parameter to an | ||
| 480 | integer. When a floating point number is given as parameter, it is | ||
| 481 | truncated 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 < 2^{bits-1}</em> | ||
| 488 | otherwise <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 RangeError | 141 | <dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError |
| 497 | exception. | 142 | exception. |
| @@ -542,70 +187,10 @@ raised if <em>a < 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 | ||
| 554 | the global floating point environment. In bigint mode, the Number | ||
| 555 | constructor returns a Float. In standard mode, it returns a SmallInt | ||
| 556 | if 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 | ||
| 567 | infinite 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 | ||
| 575 | infinite 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 | ||
| 581 | infinite 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 | ||
| 594 | return 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 | ||
| 600 | minimum (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. The | 196 | <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 | |||
| 628 | point environment is used. | 213 | point environment is used. |
| 629 | </p> | 214 | </p> |
| 630 | <p>The rounding mode of the global floating point environment is always | 215 | <p>The rounding mode of the global floating point environment is always |
| 631 | <code>RNDN</code> (“round to nearest with ties to even”)<a name="DOCF5" href="#FOOT5"><sup>5</sup></a>. The status flags of the global environment cannot be | 216 | <code>RNDN</code> (“round to nearest with ties to even”)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be |
| 632 | read<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>. The precision of the global environment is | 217 | read<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 global | 218 | <code>BigFloatEnv.prec</code>. The number of exponent bits of the global |
| 634 | environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is | 219 | environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is |
| 635 | strictly smaller than the maximum allowed number of exponent bits | 220 | strictly smaller than the maximum allowed number of exponent bits |
| @@ -646,7 +231,7 @@ when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a · 10 unmodified lines | |||
| 646 | function can change the global floating point environment for its | 231 | function can change the global floating point environment for its |
| 647 | callees but not for its caller. | 232 | callees 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 if | 237 | <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> |
| 670 | suffix. BigFloat literals have an infinite precision. They are rounded | 255 | suffix. BigFloat literals have an infinite precision. They are rounded |
| 671 | according to the global floating point environment when they are | 256 | according to the global floating point environment when they are |
| 672 | evaluated.<a name="DOCF7" href="#FOOT7"><sup>7</sup></a> | 257 | evaluated.<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) or | 333 | <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, | ||
| 384 | 16 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 with | 390 | <dd><p>Same semantics as the corresponding <code>Number</code> functions with |
| 795 | BigFloats. There is no limit on the accepted precision <code>p</code>. The | 391 | BigFloats. There is no limit on the accepted precision <code>p</code>. The |
| 796 | rounding mode can be optionally specified. It is set by default to | 392 | rounding mode and radix can be optionally specified. The radix must be |
| 797 | <code>BigFloatEnv.RNDNA</code>. | 393 | between 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 point | 430 | <dd><p>Getter. Return the precision in bits of the global floating point |
| 835 | environment. The initial value is <code>53</code>. | 431 | environment. 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 point | 435 | <dd><p>Getter. Return the exponent size in bits of the global floating point |
| 840 | environment assuming an IEEE 754 representation. If <code>expBits < | 436 | environment assuming an IEEE 754 representation. If <code>expBits < |
| 841 | expBitsMax</code>, then subnormal numbers are supported. The initial value | 437 | expBitsMax</code>, then subnormal numbers are supported. The initial value |
| 842 | is <code>11</code>. | 438 | is <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 to | 444 | <code>f</code>. Then the Float precision and exponent size are reset to |
| 849 | their precious value and the return value of <code>f</code> is returned (or | 445 | their precious value and the return value of <code>f</code> is returned (or |
| 850 | an exception is raised if <code>f</code> raised an exception). If <code>e</code> | 446 | an exception is raised if <code>f</code> raised an exception). If <code>e</code> |
| 851 | is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>. <code>p</code> | 447 | is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>. |
| 852 | must be >= 53 and <code>e</code> must be >= 11 so that the global precision | ||
| 853 | is 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 in | 464 | <dd><p>Read-only integer. Return the maximum allowed exponent size in |
| 871 | bits. Must be at least 11. | 465 | bits. 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 is | 493 | <dd><p>Read-only integer. Faithful rounding mode. The result is |
| 900 | non-deterministically rounded to -Infinity or +Infinity. This rounding | 494 | non-deterministically rounded to -Infinity or +Infinity. This rounding |
| 901 | mode usually gives a faster and deterministic running time for the | 495 | mode 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 | ||
| 541 | 10. 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 | ||
| 545 | finite. 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 | ||
| 547 | precision. | ||
| 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 is | 556 | <dt><code>-</code></dt> |
| 950 | returned 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 | ||
| 559 | precision. | ||
| 560 | </p></dd> | ||
| 561 | <dt><code>%</code></dt> | ||
| 562 | <dd><p>Both operands must be BigDecimal. The result is computed with infinite | ||
| 563 | precision. 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) | 568 | division by zero or if the result cannot be represented with infinite |
| 956 | value, so <code>BigFloat</code> values are accepted. When a <code>BigFloat</code> | 569 | precision (use <code>BigDecimal.div</code> to specify the rounding). |
| 957 | is 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 | ||
| 574 | integer. 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 | ||
| 579 | are a BigDecimal and if they are equal. | ||
| 580 | </p> | ||
| 581 | </dd> | ||
| 582 | <dt><code>==</code></dt> | ||
| 583 | <dt><code>!=</code></dt> | ||
| 584 | <dt><code><=</code></dt> | ||
| 585 | <dt><code>>=</code></dt> | ||
| 586 | <dt><code><</code></dt> | ||
| 587 | <dt><code>></code></dt> | ||
| 588 | <dd> | ||
| 589 | <p>Numerical comparison. When one of the operand is not a BigDecimal, it is | ||
| 590 | converted to BigDecimal by using ToString(). Hence comparisons between | ||
| 591 | Number and BigDecimal do not use the exact mathematical value of the | ||
| 592 | Number 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>"use math"</code> | 606 | <a name="The-BigDecimal-function_002e"></a> |
| 969 | directive. <code>"use bigint"</code> is implied in math mode. With this | 607 | <h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4> |
| 970 | mode, writing mathematical expressions is more intuitive, exact | 608 | |
| 971 | results (e.g. fractions) can be computed for all operators and floating | 609 | <p>It returns <code>0m</code> if no parameter is provided. Otherwise the first |
| 972 | point literals have the <code>BigFloat</code> type by default. | 610 | parameter is converted to a bigdecimal by using ToString(). Hence |
| 611 | Number value are not converted to their exact numerical value as | ||
| 612 | BigDecimal. | ||
| 973 | </p> | 613 | </p> |
| 974 | <p>It propagates the same way as the <em>strict mode</em>. In | 614 | <a name="Properties-of-the-BigDecimal-object"></a> |
| 975 | this 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 | ||
| 626 | point result according to the rounding object <code>e</code>. If the | ||
| 627 | rounding object is not present, the operation is executed with | ||
| 628 | infinite 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>). | 631 | division by zero or if the result cannot be represented with infinite |
| 632 | precision 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 | ||
| 635 | zero. | ||
| 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>"floor"</code>, <code>"ceiling"</code>, <code>"down"</code>, <code>"up"</code>, | ||
| 640 | <code>"half-even"</code>, <code>"half-up"</code>). Either | ||
| 641 | <code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must | ||
| 642 | be present to specify respectively the number of significant digits | ||
| 643 | (must be >= 1) or the number of digits after the decimal point (must | ||
| 644 | be >= 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 = "half-up")</code></dt> | ||
| 662 | <dt><code>toFixed(p, rnd_mode = "half-up")</code></dt> | ||
| 663 | <dt><code>toExponential(p, rnd_mode = "half-up")</code></dt> | ||
| 664 | <dd><p>Convert the BigDecimal <code>this</code> to string with the specified | ||
| 665 | precision <code>p</code>. There is no limit on the accepted precision | ||
| 666 | <code>p</code>. The rounding mode can be optionally | ||
| 667 | specified. <code>toPrecision</code> outputs either in decimal fixed notation | ||
| 668 | or in decimal exponential notation with a <code>p</code> digits of | ||
| 669 | precision. <code>toExponential</code> outputs in decimal exponential | ||
| 670 | notation with <code>p</code> digits after the decimal point. <code>toFixed</code> | ||
| 671 | outputs in decimal notation with <code>p</code> digits after the decimal | ||
| 672 | point. | ||
| 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>"use math"</code> |
| 681 | directive. It propagates the same way as the <em>strict mode</em>. It is | ||
| 682 | designed so that arbitrarily large integers and floating point numbers | ||
| 683 | are available by default. In order to minimize the number of changes | ||
| 684 | in the Javascript semantics, integers are represented either as Number | ||
| 685 | or BigInt depending on their magnitude. Floating point numbers are | ||
| 686 | always 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 === "bigfloat"</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 === "number "</code>, <code>typeof 1n === "number"</code> but <code>typeof 9007199254740992 === "bigint" </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>The | 718 | <p>The |
| 1027 | rationale is that the rounding mode changes must always be | 719 | rationale is that the rounding mode changes must always be |
| 1028 | explicit.</p> | 720 | explicit.</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-in | 722 | <p>The rationale is to avoid side effects for the built-in |
| 1031 | operators.</p> | 723 | operators.</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 be | 725 | <p>Base 10 floating point literals cannot usually be |
| 1034 | exactly represented as base 2 floating point number. In order to | 726 | exactly represented as base 2 floating point number. In order to |
| 1035 | ensure that the literal is represented accurately with the current | 727 | ensure that the literal is represented accurately with the current |
| 1036 | precision, it must be evaluated at runtime.</p> | 728 | precision, 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> |
Binary file not shown.
| @@ -10,12 +10,12 @@ · 9 unmodified lines | |||
| 10 | @sp 7 | 10 | @sp 7 |
| 11 | @center @titlefont{Javascript Bignum Extensions} | 11 | @center @titlefont{Javascript Bignum Extensions} |
| 12 | @sp 3 | 12 | @sp 3 |
| 13 | @center Version 2018-06-16 | 13 | @center Version 2020-01-11 |
| 14 | @sp 3 | 14 | @sp 3 |
| 15 | @center Author: Fabrice Bellard | 15 | @center Author: Fabrice Bellard |
| 16 | @end titlepage | 16 | @end titlepage |
| 17 | 17 | ||
| 18 | @setfilename spec.info | 18 | @setfilename jsbignum.info |
| 19 | @settitle Javascript Bignum Extensions | 19 | @settitle Javascript Bignum Extensions |
| 20 | 20 | ||
| 21 | @contents | 21 | @contents |
| @@ -27,348 +27,52 @@ language while being 100% backward compatible: · 5 unmodified lines | |||
| 27 | 27 | ||
| 28 | @itemize | 28 | @itemize |
| 29 | 29 | ||
| 30 | @item Overloading of the standard operators | 30 | @item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}. |
| 31 | to 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 | ||
| 38 | remainder. @code{^} is an alias to the power operator | ||
| 39 | (@code{**}). @code{^^} is used as the exclusive or operator. | ||
| 38 | 40 | ||
| 39 | @end itemize | 41 | @end itemize |
| 40 | 42 | ||
| 41 | The extensions are independent from each other except the @code{math} | 43 | The extensions are independent from each other except the @code{math} |
| 42 | mode which relies on the bigint mode and the operator overloading. | 44 | mode which relies on BigFloat and operator overloading. |
| 43 | 45 | ||
| 44 | @chapter Operator overloading | 46 | @chapter Operator overloading |
| 45 | 47 | ||
| 46 | @section Introduction | 48 | Operator overloading is inspired from the proposal available at |
| 47 | 49 | @url{https://github.com/tc39/proposal-operator-overloading/}. It | |
| 48 | If the operands of an operator have at least one object type, a custom | 50 | implements the same dispatch logic but finds the operator sets by |
| 49 | operator method is searched before doing the legacy Javascript | 51 | looking at the @code{Symbol.operatorSet} property in the objects. The |
| 50 | @code{ToNumber} conversion. | 52 | changes were done in order to simplify the implementation. |
| 51 | |||
| 52 | For unary operators, the custom function is looked up in the object | ||
| 53 | and 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 | |||
| 73 | For binary operators: | ||
| 74 | |||
| 75 | @itemize | ||
| 76 | |||
| 77 | @item | ||
| 78 | If both operands have the same constructor function, then the operator | ||
| 79 | is looked up in the constructor. | ||
| 80 | |||
| 81 | @item | ||
| 82 | Otherwise, the property @code{Symbol.operatorOrder} is looked up in both | ||
| 83 | constructors and converted to @code{Int32}. The operator is then | ||
| 84 | looked in the constructor with the larger @code{Symbol.operatorOrder} | ||
| 85 | value. A @code{TypeError} is raised if both constructors have the same | ||
| 86 | @code{Symbol.operatorOrder} value. | ||
| 87 | |||
| 88 | @end itemize | ||
| 89 | |||
| 90 | The 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 | |||
| 146 | The 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 | |||
| 153 | The 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 Introduction | 54 | More precisely, the following modifications were made: |
| 181 | |||
| 182 | The bigint mode is enabled with the @code{"use bigint"} directive. It | ||
| 183 | propagates the same way as the strict mode. In bigint mode, all | ||
| 184 | integers are considered as @code{bigint} (arbitrarily large integer, | ||
| 185 | similar to the TC39 BigInt | ||
| 186 | proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}}) | ||
| 187 | instead of @code{number} (floating point number). In order to be able | ||
| 188 | to exchange data between standard and bigint modes, numbers are | ||
| 189 | internally represented as 3 different types: | ||
| 190 | 55 | ||
| 191 | @itemize | 56 | @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 | |||
| 201 | In standard mode, the semantics of each operation is modified so that | ||
| 202 | when it returns a @code{number}, it is either of SmallInt or | ||
| 203 | Float. But the difference between SmallInt and Float is not observable | ||
| 204 | in standard mode. | ||
| 205 | |||
| 206 | In bigint mode, each operation behaves differently whether its | ||
| 207 | operands are integer or float. The difference between SmallInt and | ||
| 208 | BigInt is not observable (i.e. they are both integers). | ||
| 209 | |||
| 210 | The 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 | |||
| 223 | There is no incompatibility with Javascript. | ||
| 224 | |||
| 225 | @subsection Bigint mode | ||
| 226 | |||
| 227 | The 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 | |||
| 253 | The operands are converted to number values as in normal | ||
| 254 | Javascript. Then the general case is that an Integer is returned if | ||
| 255 | both operands are Integer. Otherwise, a float is returned. | ||
| 256 | |||
| 257 | The @code{+} operator also accepts strings as input and behaves like | ||
| 258 | standard Javascript in this case. | ||
| 259 | |||
| 260 | The binary operator @code{%} returns the truncated remainder of the | ||
| 261 | division. When the result is an Integer type, a dividend of zero yields a | ||
| 262 | RangeError exception. | ||
| 263 | |||
| 264 | The binary operator @code{%} in math mode returns the Euclidian | ||
| 265 | remainder of the division i.e. it is always positive. | ||
| 266 | |||
| 267 | The binary operator @code{/} returns a float. | ||
| 268 | |||
| 269 | The binary operator @code{/} in math mode returns a float if one of | ||
| 270 | the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is | ||
| 271 | invoked. | ||
| 272 | |||
| 273 | The returned type of @code{a ** b} is Float if @math{a} or @math{b} | ||
| 274 | are 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 itemize | 68 | @end itemize |
| 280 | 69 | ||
| 281 | The unary @code{-} and unary @code{+} return the same type as their | 70 | @chapter BigInt extensions |
| 282 | operand. They performs no floating point rounding when the result is a | ||
| 283 | float. | ||
| 284 | |||
| 285 | The unary operators @code{++} and @code{--} return the same type as | ||
| 286 | their operand. | ||
| 287 | |||
| 288 | In standard mode: | ||
| 289 | |||
| 290 | If the operator returns an Integer and that the result fits a | ||
| 291 | SmallInt, it is converted to SmallInt. Otherwise, the Integer is | ||
| 292 | converted to a Float. | ||
| 293 | |||
| 294 | In bigint mode: | ||
| 295 | |||
| 296 | If the operator returns an Integer and that the result fits a | ||
| 297 | SmallInt, it is converted to SmallInt. Otherwise it is a BigInt. | ||
| 298 | |||
| 299 | @subsection Logical operators | ||
| 300 | |||
| 301 | In standard mode: | ||
| 302 | |||
| 303 | The operands have their standard behavior. If the result fits a | ||
| 304 | SmallInt it is converted to a SmallInt. Otherwise it is a Float. | ||
| 305 | |||
| 306 | In bigint mode: | ||
| 307 | |||
| 308 | The operands are converted to integer values. The floating point | ||
| 309 | values are converted to integer by rounding them to zero. | ||
| 310 | |||
| 311 | The logical operators are defined assuming the integers are | ||
| 312 | represented in two complement notation. | ||
| 313 | |||
| 314 | For @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 | |||
| 318 | The operator @code{>>>} is supported for backward compatibility and | ||
| 319 | behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}. | ||
| 320 | 71 | ||
| 321 | If the result fits a SmallInt it is converted to a SmallInt. Otherwise | 72 | A few properties are added to the BigInt object: |
| 322 | it is a BigInt. | ||
| 323 | |||
| 324 | @subsection Relational operators | ||
| 325 | |||
| 326 | The relational operators <, <=, >, >=, ==, != work as expected with | ||
| 327 | integers and floating point numbers (e.g. @code{1.0 == 1} is true). | ||
| 328 | |||
| 329 | The strict equality operators === and !== have the usual Javascript | ||
| 330 | semantics. In particular, different types never equal, so @code{1.0 | ||
| 331 | === 1} is false. | ||
| 332 | |||
| 333 | @section Number literals | ||
| 334 | |||
| 335 | Number literals in bigint mode have a slightly different behavior than | ||
| 336 | in standard Javascript: | ||
| 337 | |||
| 338 | @enumerate | ||
| 339 | |||
| 340 | @item | ||
| 341 | A number literal without a decimal point or an exponent is considered | ||
| 342 | as an Integer. Otherwise it is a Float. | ||
| 343 | |||
| 344 | @item | ||
| 345 | Hexadecimal, octal or binary floating point literals are accepted with | ||
| 346 | a 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 | ||
| 348 | C99. 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 | |||
| 356 | The @code{BigInt} function cannot be invoked as a constructor. When | ||
| 357 | invoked as a function, it converts its first parameter to an | ||
| 358 | integer. When a floating point number is given as parameter, it is | ||
| 359 | truncated to an integer with infinite precision. | ||
| 360 | |||
| 361 | @code{BigInt} properties: | ||
| 362 | 73 | ||
| 363 | @table @code | 74 | @table @code |
| 364 | 75 | ||
| 365 | @item asIntN(bits, a) | ||
| 366 | Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}} | ||
| 367 | otherwise @math{b-2^{bits}}. | ||
| 368 | |||
| 369 | @item asUintN(bits, a) | ||
| 370 | Return @math{a \pmod{2^{bits}}}. | ||
| 371 | |||
| 372 | @item tdiv(a, b) | 76 | @item tdiv(a, b) |
| 373 | Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError | 77 | Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError |
| 374 | exception. | 78 | exception. |
| @@ -410,58 +114,7 @@ Return the number of trailing zeros in the two's complement binary representatio · 35 unmodified lines | |||
| 410 | 114 | ||
| 411 | @end table | 115 | @end table |
| 412 | 116 | ||
| 413 | @subsection @code{BigInt.prototype} | 117 | @chapter BigFloat |
| 414 | |||
| 415 | It is a normal object. | ||
| 416 | |||
| 417 | @subsection @code{Number} constructor | ||
| 418 | |||
| 419 | The number constructor returns its argument rounded to a Float using | ||
| 420 | the global floating point environment. In bigint mode, the Number | ||
| 421 | constructor returns a Float. In standard mode, it returns a SmallInt | ||
| 422 | if the value fits it, otherwise a Float. | ||
| 423 | |||
| 424 | @subsection @code{Number.prototype} | ||
| 425 | |||
| 426 | The following properties are modified: | ||
| 427 | |||
| 428 | @table @code | ||
| 429 | @item toString(radix) | ||
| 430 | |||
| 431 | In bigint mode, integers are converted to the specified radix with | ||
| 432 | infinite precision. | ||
| 433 | |||
| 434 | @item toPrecision(p) | ||
| 435 | @item toFixed(p) | ||
| 436 | @item toExponential(p) | ||
| 437 | |||
| 438 | In bigint mode, integers are accepted and converted to string with | ||
| 439 | infinite precision. | ||
| 440 | |||
| 441 | @item parseInt(string, radix) | ||
| 442 | |||
| 443 | In bigint mode, an integer is returned and the conversion is done with | ||
| 444 | infinite precision. | ||
| 445 | |||
| 446 | @end table | ||
| 447 | |||
| 448 | @subsection @code{Math} object | ||
| 449 | |||
| 450 | The following properties are modified: | ||
| 451 | |||
| 452 | @table @code | ||
| 453 | @item abs(x) | ||
| 454 | Absolute value. Return an integer if @code{x} is an Integer. Otherwise | ||
| 455 | return a Float. No rounding is performed. | ||
| 456 | |||
| 457 | @item min(a, b) | ||
| 458 | @item max(a, b) | ||
| 459 | No rounding is performed. The returned type is the same one as the | ||
| 460 | minimum (resp. maximum) value. | ||
| 461 | |||
| 462 | @end table | ||
| 463 | |||
| 464 | @chapter Arbitrarily large floating point numbers | ||
| 465 | 118 | ||
| 466 | @section Introduction | 119 | @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) |
| 591 | Round to an integer. No additional rounding is performed. | 244 | Round to an integer. No additional rounding is performed. |
| 592 | 245 | ||
| 246 | @item abs(x) | ||
| 247 | Return 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]) |
| 595 | Floating point remainder. The quotient is truncated to zero (fmod) or | 251 | Floating 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 | |||
| 620 | The following properties are modified: | 276 | The following properties are modified: |
| 621 | 277 | ||
| 622 | @table @code | 278 | @table @code |
| 279 | @item valueOf() | ||
| 280 | Return the bigfloat primitive value corresponding to @code{this}. | ||
| 281 | |||
| 623 | @item toString(radix) | 282 | @item toString(radix) |
| 624 | 283 | ||
| 625 | For floating point numbers: | 284 | For 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 itemize | 296 | @end itemize |
| 638 | 297 | ||
| 639 | @item toPrecision(p[, rnd_mode]) | 298 | The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8, |
| 640 | @item toFixed(p[, rnd_mode]) | 299 | 16 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) | ||
| 642 | Same semantics as the corresponding @code{Number} functions with | 304 | Same semantics as the corresponding @code{Number} functions with |
| 643 | BigFloats. There is no limit on the accepted precision @code{p}. The | 305 | BigFloats. There is no limit on the accepted precision @code{p}. The |
| 644 | rounding mode can be optionally specified. It is set by default to | 306 | rounding mode and radix can be optionally specified. The radix must be |
| 645 | @code{BigFloatEnv.RNDNA}. | 307 | between 2 and 36. |
| 646 | 308 | ||
| 647 | @end table | 309 | @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 prec | 342 | @item prec |
| 681 | Getter. Return the precision in bits of the global floating point | 343 | Getter. Return the precision in bits of the global floating point |
| 682 | environment. The initial value is @code{53}. | 344 | environment. The initial value is @code{113}. |
| 683 | 345 | ||
| 684 | @item expBits | 346 | @item expBits |
| 685 | Getter. Return the exponent size in bits of the global floating point | 347 | Getter. Return the exponent size in bits of the global floating point |
| 686 | environment assuming an IEEE 754 representation. If @code{expBits < | 348 | environment assuming an IEEE 754 representation. If @code{expBits < |
| 687 | expBitsMax}, then subnormal numbers are supported. The initial value | 349 | expBitsMax}, then subnormal numbers are supported. The initial value |
| 688 | is @code{11}. | 350 | is @code{15}. |
| 689 | 351 | ||
| 690 | @item setPrec(f, p[, e]) | 352 | @item setPrec(f, p[, e]) |
| 691 | Set the precision of the global floating point environment to @code{p} | 353 | Set the precision of the global floating point environment to @code{p} |
| @@ -693,15 +355,13 @@ and the exponent size to @code{e} then call the function · 1 unmodified line | |||
| 693 | @code{f}. Then the Float precision and exponent size are reset to | 355 | @code{f}. Then the Float precision and exponent size are reset to |
| 694 | their precious value and the return value of @code{f} is returned (or | 356 | their precious value and the return value of @code{f} is returned (or |
| 695 | an exception is raised if @code{f} raised an exception). If @code{e} | 357 | an exception is raised if @code{f} raised an exception). If @code{e} |
| 696 | is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. @code{p} | 358 | is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. |
| 697 | must be >= 53 and @code{e} must be >= 11 so that the global precision | ||
| 698 | is at least equivalent to the IEEE 754 64 bit doubles. | ||
| 699 | 359 | ||
| 700 | @item precMin | 360 | @item precMin |
| 701 | Read-only integer. Return the minimum allowed precision. Must be at least 2. | 361 | Read-only integer. Return the minimum allowed precision. Must be at least 2. |
| 702 | 362 | ||
| 703 | @item precMax | 363 | @item precMax |
| 704 | Read-only integer. Return the maximum allowed precision. Must be at least 53. | 364 | Read-only integer. Return the maximum allowed precision. Must be at least 113. |
| 705 | 365 | ||
| 706 | @item expBitsMin | 366 | @item expBitsMin |
| 707 | Read-only integer. Return the minimum allowed exponent size in | 367 | Read-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 expBitsMax | 370 | @item expBitsMax |
| 711 | Read-only integer. Return the maximum allowed exponent size in | 371 | Read-only integer. Return the maximum allowed exponent size in |
| 712 | bits. Must be at least 11. | 372 | bits. Must be at least 15. |
| 713 | 373 | ||
| 714 | @item RNDN | 374 | @item RNDN |
| 715 | Read-only integer. Round to nearest, with ties to even rounding mode. | 375 | Read-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 RNDNA | 386 | @item RNDNA |
| 727 | Read-only integer. Round to nearest, with ties away from zero rounding mode. | 387 | Read-only integer. Round to nearest, with ties away from zero rounding mode. |
| 728 | 388 | ||
| 729 | @item RNDNU | 389 | @item RNDA |
| 730 | Read-only integer. Round to nearest, with ties to +Infinity rounding mode. | 390 | Read-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.} |
| 733 | Read-only integer. Faithful rounding mode. The result is | 393 | Read-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 table | 428 | @end table |
| 769 | 429 | ||
| 770 | @subsection @code{Math} object | 430 | @chapter BigDecimal |
| 771 | 431 | ||
| 772 | The following properties are modified: | 432 | This extension adds the @code{BigDecimal} primitive type. The |
| 433 | @code{BigDecimal} type represents floating point numbers in base | ||
| 434 | 10. It is inspired from the proposal available at | ||
| 435 | @url{https://github.com/littledan/proposal-bigdecimal}. | ||
| 436 | |||
| 437 | The @code{BigDecimal} floating point numbers are always normalized and | ||
| 438 | finite. There is no concept of @code{-0}, @code{Infinity} or | ||
| 439 | @code{NaN}. By default, all the computations are done with infinite | ||
| 440 | precision. | ||
| 441 | |||
| 442 | @section Operators | ||
| 443 | |||
| 444 | The following builtin operators support BigDecimal: | ||
| 773 | 445 | ||
| 774 | @table @code | 446 | @table @code |
| 775 | @item abs(x) | ||
| 776 | Absolute value. If @code{x} is a BigFloat, its absolute value is | ||
| 777 | returned as a BigFloat. No rounding is performed. | ||
| 778 | 447 | ||
| 779 | @item min(a, b) | 448 | @item + |
| 780 | @item max(a, b) | 449 | @item - |
| 781 | The returned type is the same one as the minimum (resp. maximum) | 450 | @item * |
| 782 | value, so @code{BigFloat} values are accepted. When a @code{BigFloat} | 451 | Both operands must be BigDecimal. The result is computed with infinite |
| 783 | is returned, no rounding is performed. | 452 | precision. |
| 453 | @item % | ||
| 454 | Both operands must be BigDecimal. The result is computed with infinite | ||
| 455 | precision. A range error is throws in case of division by zero. | ||
| 784 | 456 | ||
| 785 | @end table | 457 | @item / |
| 458 | Both operands must be BigDecimal. A range error is throws in case of | ||
| 459 | division by zero or if the result cannot be represented with infinite | ||
| 460 | precision (use @code{BigDecimal.div} to specify the rounding). | ||
| 786 | 461 | ||
| 787 | @chapter Math mode | 462 | @item ** |
| 463 | Both operands must be BigDecimal. The exponent must be a positive | ||
| 464 | integer. The result is computed with infinite precision. | ||
| 788 | 465 | ||
| 789 | @section Introduction | 466 | @item === |
| 467 | When one of the operand is a BigDecimal, return true if both operands | ||
| 468 | are a BigDecimal and if they are equal. | ||
| 790 | 469 | ||
| 791 | A new @emph{math mode} is enabled with the @code{"use math"} | 470 | @item == |
| 792 | directive. @code{"use bigint"} is implied in math mode. With this | 471 | @item != |
| 793 | mode, writing mathematical expressions is more intuitive, exact | 472 | @item <= |
| 794 | results (e.g. fractions) can be computed for all operators and floating | 473 | @item >= |
| 795 | point literals have the @code{BigFloat} type by default. | 474 | @item < |
| 475 | @item > | ||
| 796 | 476 | ||
| 797 | It propagates the same way as the @emph{strict mode}. In | 477 | Numerical comparison. When one of the operand is not a BigDecimal, it is |
| 798 | this mode: | 478 | converted to BigDecimal by using ToString(). Hence comparisons between |
| 479 | Number and BigDecimal do not use the exact mathematical value of the | ||
| 480 | Number value. | ||
| 799 | 481 | ||
| 800 | @itemize | 482 | @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}. | 486 | BigDecimal 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. | 493 | It returns @code{0m} if no parameter is provided. Otherwise the first |
| 494 | parameter is converted to a bigdecimal by using ToString(). Hence | ||
| 495 | Number value are not converted to their exact numerical value as | ||
| 496 | BigDecimal. | ||
| 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 itemize | 502 | @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) | ||
| 509 | Perform the specified floating point operation and round the floating | ||
| 510 | point result according to the rounding object @code{e}. If the | ||
| 511 | rounding object is not present, the operation is executed with | ||
| 512 | infinite precision. | ||
| 817 | 513 | ||
| 818 | @section Builtin Object changes | 514 | For @code{div}, a @code{RangeError} exception is thrown in case of |
| 515 | division by zero or if the result cannot be represented with infinite | ||
| 516 | precision if no rounding object is present. | ||
| 517 | |||
| 518 | For @code{sqrt}, a range error is thrown if @code{a} is less than | ||
| 519 | zero. | ||
| 520 | |||
| 521 | The 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 | ||
| 526 | be present to specify respectively the number of significant digits | ||
| 527 | (must be >= 1) or the number of digits after the decimal point (must | ||
| 528 | be >= 0). | ||
| 819 | 529 | ||
| 820 | @subsection @code{Symbol} constructor | 530 | @end table |
| 531 | |||
| 532 | @subsection Properties of the @code{BigDecimal.prototype} object | ||
| 821 | 533 | ||
| 822 | The following global symbol is added for the operator overloading: | ||
| 823 | @table @code | 534 | @table @code |
| 824 | @item operatorMathMod | 535 | @item valueOf() |
| 536 | Return the bigdecimal primitive value corresponding to @code{this}. | ||
| 537 | |||
| 538 | @item toString() | ||
| 539 | Convert @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") | ||
| 544 | Convert the BigDecimal @code{this} to string with the specified | ||
| 545 | precision @code{p}. There is no limit on the accepted precision | ||
| 546 | @code{p}. The rounding mode can be optionally | ||
| 547 | specified. @code{toPrecision} outputs either in decimal fixed notation | ||
| 548 | or in decimal exponential notation with a @code{p} digits of | ||
| 549 | precision. @code{toExponential} outputs in decimal exponential | ||
| 550 | notation with @code{p} digits after the decimal point. @code{toFixed} | ||
| 551 | outputs in decimal notation with @code{p} digits after the decimal | ||
| 552 | point. | ||
| 553 | |||
| 825 | @end table | 554 | @end table |
| 826 | 555 | ||
| 827 | @section Remaining issues | 556 | @chapter Math mode |
| 828 | 557 | ||
| 829 | @enumerate | 558 | A new @emph{math mode} is enabled with the @code{"use math"} |
| 559 | directive. It propagates the same way as the @emph{strict mode}. It is | ||
| 560 | designed so that arbitrarily large integers and floating point numbers | ||
| 561 | are available by default. In order to minimize the number of changes | ||
| 562 | in the Javascript semantics, integers are represented either as Number | ||
| 563 | or BigInt depending on their magnitude. Floating point numbers are | ||
| 564 | always represented as BigFloat. | ||
| 565 | |||
| 566 | The 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 enumerate | 570 | @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 | @bye | 592 | @bye |
| @@ -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 | |||
| 241 | the <code>"use bigint"</code> and <code>"use math"</code> directives. | 241 | the <code>"use bigint"</code> and <code>"use math"</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 | |||
| 767 | and <code>err</code> the error code. | 772 | and <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> |
Binary file not shown.
| @@ -92,7 +92,7 @@ generates a @code{hello} executable with no external dependency. · 91 unmodified lines | |||
| 92 | @subsection @code{qjs} interpreter | 92 | @subsection @code{qjs} interpreter |
| 93 | 93 | ||
| 94 | @verbatim | 94 | @verbatim |
| 95 | usage: qjs [options] [files] | 95 | usage: qjs [options] [file [args]] |
| 96 | @end verbatim | 96 | @end verbatim |
| 97 | 97 | ||
| 98 | Options are: | 98 | Options are: |
| @@ -122,6 +122,10 @@ Load as ES6 script (default=autodetect). · 23 unmodified lines | |||
| 122 | Enable the bignum extensions: BigDecimal object, BigFloat object and | 122 | Enable the bignum extensions: BigDecimal object, BigFloat object and |
| 123 | the @code{"use bigint"} and @code{"use math"} directives. | 123 | the @code{"use bigint"} and @code{"use math"} directives. |
| 124 | 124 | ||
| 125 | @item -I file | ||
| 126 | @item --include file | ||
| 127 | Include an additional file. | ||
| 128 | |||
| 125 | @end table | 129 | @end table |
| 126 | 130 | ||
| 127 | Advanced options are: | 131 | Advanced options are: |
| @@ -576,6 +580,9 @@ pathname of @code{path} and @code{err} the error code. · 448 unmodified lines | |||
| 576 | Return @code{[str, err]} where @code{str} is the current working directory | 580 | Return @code{[str, err]} where @code{str} is the current working directory |
| 577 | and @code{err} the error code. | 581 | and @code{err} the error code. |
| 578 | 582 | ||
| 583 | @item chdir(path) | ||
| 584 | Change the current directory. Return the error code. | ||
| 585 | |||
| 579 | @item mkdir(path, mode = 0o777) | 586 | @item mkdir(path, mode = 0o777) |
| 580 | Create a directory at @code{path}. Return the error code. | 587 | Create a directory at @code{path}. Return the error code. |
| 581 | 588 | ||
| @@ -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 */ |
| 8 | function calc_pi(prec) { | 8 | function 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 | else | 34 | 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 for | 64 | /* 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 | })(); |
| @@ -86,7 +86,6 @@ static no_inline int fft_mul(bf_context_t *s, · 85 unmodified lines | |||
| 86 | static void fft_clear_cache(bf_context_t *s); | 86 | static void fft_clear_cache(bf_context_t *s); |
| 87 | #endif | 87 | #endif |
| 88 | #ifdef USE_BF_DEC | 88 | #ifdef USE_BF_DEC |
| 89 | static void mp_pow_init(void); | ||
| 90 | static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos); | 89 | static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos); |
| 91 | #endif | 90 | #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 */ | ||
| 157 | static 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 | ||
| 172 | void bf_context_end(bf_context_t *s) | 179 | void 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' is | 479 | /* 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 be | 480 | 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 of | 481 | 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. */ |
| 481 | static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l) | 484 | static 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 1 | 785 | /* Standard floating point comparison: return 2 if one of the operands |
| 784 | #define BF_CMP_LT 2 | 786 | is NaN (unordered) or -1, 0, 1 depending on the ordering assuming |
| 785 | #define BF_CMP_LE 3 | 787 | -0 == +0 */ |
| 786 | 788 | int bf_cmp(const bf_t *a, const bf_t *b) | |
| 787 | static 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 | |||
| 815 | int bf_cmp_eq(const bf_t *a, const bf_t *b) | ||
| 816 | { | ||
| 817 | return bf_cmp(a, b, BF_CMP_EQ); | ||
| 818 | } | ||
| 819 | |||
| 820 | int bf_cmp_le(const bf_t *a, const bf_t *b) | ||
| 821 | { | ||
| 822 | return bf_cmp(a, b, BF_CMP_LE); | ||
| 823 | } | ||
| 824 | |||
| 825 | int 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 | ||
| 1848 | int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, | 1824 | int 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 | |||
| 1860 | int 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 | ||
| 1881 | int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, | 1845 | int 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 stop | 2760 | /* 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 | else | 2764 | 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 | else | 3475 | 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 safely | 3480 | /* 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 | |||
| 3668 | static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, | 3638 | static 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 | else | 3665 | 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_DEC | 3747 | #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 | } else | 3767 | } else |
| 3748 | #endif | 3768 | #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 exponential | 3816 | /* max number of digits for non exponential |
| 3763 | notation. The rational is to have the same rule | 3817 | 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 | ||
| 4036 | static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags, | 4090 | static 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 | |||
| 4070 | int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags) | 4125 | int 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 | ||
| 4076 | int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags) | 4131 | /* return rounded pi * (1 - 2 * sign) */ |
| 4132 | static 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 | |||
| 4139 | int 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 | ||
| 4082 | void bf_clear_cache(bf_context_t *s) | 4144 | void 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 */ | ||
| 4201 | static 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 */ | ||
| 4288 | static 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 | |||
| 4205 | int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 4338 | int 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 */ | ||
| 4408 | static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque) | 4508 | static 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 */ | ||
| 4427 | static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) | 4529 | static 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 0 | 4739 | #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 | #endif | 4743 | #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 | ||
| 4652 | int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) | 4779 | static 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 | ||
| 4775 | int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 4881 | int 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 | ||
| 4785 | int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 4915 | int 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 | |||
| 4790 | static 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 | |||
| 4944 | static 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 | ||
| 4818 | int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 4959 | int 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 | ||
| 4946 | int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 5077 | int 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 | else | 5182 | 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 | ||
| 5057 | int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 5198 | int 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 | ||
| 5062 | int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) | 5239 | int 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 | ||
| 5127 | static inline limb_t shrd(limb_t low, limb_t high, long shift) | 5333 | static 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 | ||
| 5134 | static inline limb_t shld(limb_t a1, limb_t a0, long shift) | 5340 | static 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 | ||
| 5187 | typedef struct FastDivData { | 5393 | typedef 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" by | 5399 | /* 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 */ |
| 5198 | static inline void fast_udiv_init(FastDivData *s, limb_t d) | 5402 | static 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 | else | 5408 | 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 | ||
| 5228 | static inline limb_t fast_urem(limb_t a, const FastDivData *s) | 5431 | /* contains 10^i */ |
| 5229 | { | 5432 | const 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)->d | 5457 | /* precomputed from fast_udiv_init(10^i) */ |
| 5236 | 5458 | static 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 | #else | 5470 | #else |
| 5238 | 5471 | { 0x0000000000000001, 0, 0 }, | |
| 5239 | static 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 }, |
| 5243 | static 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 }, |
| 5247 | static 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)->d | 5485 | { 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 | #endif | 5491 | #endif |
| 5492 | }; | ||
| 5255 | 5493 | ||
| 5256 | /* contains 10^i */ | 5494 | /* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */ |
| 5257 | /* XXX: make it const */ | 5495 | static inline limb_t fast_shr_dec(limb_t a, int shift) |
| 5258 | limb_t mp_pow_dec[LIMB_DIGITS + 1]; | ||
| 5259 | static FastDivData mp_pow_div[LIMB_DIGITS + 1]; | ||
| 5260 | |||
| 5261 | static 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 | |||
| 5274 | limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, | 5503 | limb_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 0 | 6267 | #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 | else | 6286 | 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 | else | 6371 | 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 | ||
| 6759 | int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, | 6992 | int 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 == 64 | 7117 | #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 | #else | 7119 | #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); |
| @@ -41,8 +41,8 @@ typedef unsigned __int128 uint128_t; · 40 unmodified lines | |||
| 41 | typedef int64_t slimb_t; | 41 | typedef int64_t slimb_t; |
| 42 | typedef uint64_t limb_t; | 42 | typedef uint64_t limb_t; |
| 43 | typedef uint128_t dlimb_t; | 43 | typedef uint128_t dlimb_t; |
| 44 | #define EXP_MIN INT64_MIN | 44 | #define BF_RAW_EXP_MIN INT64_MIN |
| 45 | #define EXP_MAX INT64_MAX | 45 | #define BF_RAW_EXP_MAX INT64_MAX |
| 46 | 46 | ||
| 47 | #define LIMB_DIGITS 19 | 47 | #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 | |||
| 52 | typedef int32_t slimb_t; | 52 | typedef int32_t slimb_t; |
| 53 | typedef uint32_t limb_t; | 53 | typedef uint32_t limb_t; |
| 54 | typedef uint64_t dlimb_t; | 54 | typedef uint64_t dlimb_t; |
| 55 | #define EXP_MIN INT32_MIN | 55 | #define BF_RAW_EXP_MIN INT32_MIN |
| 56 | #define EXP_MAX INT32_MAX | 56 | #define BF_RAW_EXP_MAX INT32_MAX |
| 57 | 57 | ||
| 58 | #define LIMB_DIGITS 9 | 58 | #define LIMB_DIGITS 9 |
| 59 | #define BF_DEC_BASE 1000000000U | 59 | #define BF_DEC_BASE 1000000000U |
| @@ -61,10 +61,17 @@ typedef uint64_t dlimb_t; · 1 unmodified line | |||
| 61 | #endif | 61 | #endif |
| 62 | 62 | ||
| 63 | /* in bits */ | 63 | /* in bits */ |
| 64 | /* minimum number of bits for the exponent */ | ||
| 64 | #define BF_EXP_BITS_MIN 3 | 65 | #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 2 | 71 | #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 == 64 | 77 | #if LIMB_BITS == 64 |
| @@ -73,9 +80,9 @@ typedef uint64_t dlimb_t; · 2 unmodified lines | |||
| 73 | #define BF_CHKSUM_MOD 975620677U | 80 | #define BF_CHKSUM_MOD 975620677U |
| 74 | #endif | 81 | #endif |
| 75 | 82 | ||
| 76 | #define BF_EXP_ZERO EXP_MIN | 83 | #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_MAX | 85 | #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 | |||
| 101 | typedef enum { | 108 | typedef 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 exponent | 119 | /* allow subnormal numbers. Only available if the number of exponent |
| 113 | bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF. Not supported | 120 | 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 whole | 122 | /* 'prec' is the precision after the radix point instead of the whole |
| 117 | mantissa. Can only be used with bf_round(), bfdec_round() and | 123 | 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 0x7 | 127 | #define BF_RND_MASK 0x7 |
| 122 | #define BF_EXP_BITS_SHIFT 5 | 128 | #define BF_EXP_BITS_SHIFT 5 |
| 123 | #define BF_EXP_BITS_MASK 0x3f | 129 | #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 */ |
| 126 | typedef uint32_t bf_flags_t; | 135 | typedef uint32_t bf_flags_t; |
| 127 | 136 | ||
| @@ -142,12 +151,17 @@ typedef struct bf_context_t { · 14 unmodified lines | |||
| 142 | 151 | ||
| 143 | static inline int bf_get_exp_bits(bf_flags_t flags) | 152 | static 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 | ||
| 148 | static inline bf_flags_t bf_set_exp_bits(int n) | 162 | static 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 | ||
| 250 | int bf_cmpu(const bf_t *a, const bf_t *b); | 264 | int bf_cmpu(const bf_t *a, const bf_t *b); |
| 251 | int bf_cmp_full(const bf_t *a, const bf_t *b); | 265 | int bf_cmp_full(const bf_t *a, const bf_t *b); |
| 252 | int bf_cmp_eq(const bf_t *a, const bf_t *b); | 266 | int bf_cmp(const bf_t *a, const bf_t *b); |
| 253 | int bf_cmp_le(const bf_t *a, const bf_t *b); | 267 | static inline int bf_cmp_eq(const bf_t *a, const bf_t *b) |
| 254 | int bf_cmp_lt(const bf_t *a, const bf_t *b); | 268 | { |
| 269 | return bf_cmp(a, b) == 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | static inline int bf_cmp_le(const bf_t *a, const bf_t *b) | ||
| 273 | { | ||
| 274 | return bf_cmp(a, b) <= 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static inline int bf_cmp_lt(const bf_t *a, const bf_t *b) | ||
| 278 | { | ||
| 279 | return bf_cmp(a, b) < 0; | ||
| 280 | } | ||
| 281 | |||
| 255 | int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); | 282 | int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); |
| 256 | int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); | 283 | int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); |
| 257 | int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); | 284 | int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); |
| @@ -264,12 +291,10 @@ int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags) · 6 unmodified lines | |||
| 264 | #define BF_DIVREM_EUCLIDIAN BF_RNDF | 291 | #define BF_DIVREM_EUCLIDIAN BF_RNDF |
| 265 | int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, | 292 | int 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); |
| 267 | int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, | 294 | int 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); |
| 269 | int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, | ||
| 270 | bf_flags_t flags); | ||
| 271 | int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, | 296 | int 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 */ |
| 274 | int bf_rint(bf_t *r, int rnd_mode); | 299 | int bf_rint(bf_t *r, int rnd_mode); |
| 275 | int bf_round(bf_t *r, limb_t prec, bf_flags_t flags); | 300 | int bf_round(bf_t *r, limb_t prec, bf_flags_t flags); |
| @@ -304,8 +329,8 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 28 unmodified lines | |||
| 304 | /* Conversion of floating point number to string. Return a null | 329 | /* Conversion of floating point number to string. Return a null |
| 305 | terminated string or NULL if memory error. *plen contains its | 330 | 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 the | 332 | "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 with | 341 | /* 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 to | 345 | |
| 321 | nearest and the subnormal+exponent configuration of 'flags'. The | 346 | 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 wanted | 347 | 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 a | 350 | 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 digits | 358 | /* 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 | |||
| 370 | int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags); | 401 | int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags); |
| 371 | int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); | 402 | int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); |
| 372 | int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); | 403 | int 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 */ |
| 374 | int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags); | 405 | int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags); |
| 375 | int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); | 406 | int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); |
| 376 | int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); | 407 | int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); |
| @@ -448,17 +479,21 @@ static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b) · 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 | } |
| 482 | static 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 | } | ||
| 451 | static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b) | 486 | static 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 | } |
| 455 | static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b) | 490 | static 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 | } |
| 459 | static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b) | 494 | static 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 | ||
| 464 | int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, | 499 | int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, |
| @@ -475,8 +510,8 @@ int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, · 10 unmodified lines | |||
| 475 | bf_flags_t flags); | 510 | bf_flags_t flags); |
| 476 | int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, | 511 | int 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); |
| 478 | int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, | 513 | int 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); |
| 480 | int bfdec_rint(bfdec_t *r, int rnd_mode); | 515 | int bfdec_rint(bfdec_t *r, int rnd_mode); |
| 481 | int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags); | 516 | int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags); |
| 482 | int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags); | 517 | int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags); |
| @@ -488,7 +523,7 @@ int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, · 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. */ |
| 491 | extern limb_t mp_pow_dec[LIMB_DIGITS + 1]; | 526 | extern const limb_t mp_pow_dec[LIMB_DIGITS + 1]; |
| 492 | void bfdec_print_str(const char *str, const bfdec_t *a); | 527 | void bfdec_print_str(const char *str, const bfdec_t *a); |
| 493 | static inline int bfdec_resize(bfdec_t *r, limb_t len) | 528 | static inline int bfdec_resize(bfdec_t *r, limb_t len) |
| 494 | { | 529 | { |
| @@ -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 | |||
| 47 | extern const uint8_t qjsc_repl[]; | 44 | extern const uint8_t qjsc_repl[]; |
| 48 | extern const uint32_t qjsc_repl_size; | 45 | extern const uint32_t qjsc_repl_size; |
| 49 | #ifdef CONFIG_BIGNUM | 46 | #ifdef CONFIG_BIGNUM |
| @@ -258,12 +255,13 @@ static const JSMallocFunctions trace_mf = { · 208 unmodified lines | |||
| 258 | void help(void) | 255 | void 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_BIGNUM | 266 | #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_BIGNUM | 295 | #ifdef CONFIG_BIGNUM |
| 296 | int load_jscalc, bignum_ext = 0; | 296 | int load_jscalc, bignum_ext = 0; |
| 297 | #endif | 297 | #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 | #endif | 444 | #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; |
| @@ -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 | |||
| 42 | typedef struct { | 39 | typedef 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 9 | 77 | #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 | ||
| 85 | void namelist_add(namelist_t *lp, const char *name, const char *short_name, | 84 | void 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 | #endif | 626 | #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++) { |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * QuickJS Javascript Calculator | 2 | * QuickJS Javascript Calculator |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2017-2018 Fabrice Bellard | 4 | * Copyright (c) 2017-2020 Fabrice Bellard |
| 5 | * | 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal | 7 | * of this software and associated documentation files (the "Software"), to deal |
| @@ -27,20 +27,8 @@ · 19 unmodified lines | |||
| 27 | var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix; | 27 | var 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 | else | 528 | 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 | else | 553 | 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 | else | 781 | 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 | else | 1220 | } |
| 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 even | 1543 | /* This function always return a RationalFunction object even |
| 1384 | if it could simplified to a polynomial, so it is not | 1544 | 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 | ||
| 2592 | function sinh(a) | ||
| 2593 | { | ||
| 2594 | var e = Float.exp(Float(a)); | ||
| 2595 | return (e - 1/e) * 0.5; | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | function cosh(a) | ||
| 2599 | { | ||
| 2600 | var e = Float.exp(Float(a)); | ||
| 2601 | return (e + 1/e) * 0.5; | ||
| 2602 | } | ||
| 2603 | |||
| 2604 | function tanh(a) | ||
| 2605 | { | ||
| 2606 | var e = Float.exp(Float(a) * 2); | ||
| 2607 | return (e - 1) / (e + 1); | ||
| 2608 | } | ||
| 2609 | |||
| 2610 | function asinh(a) | ||
| 2611 | { | ||
| 2612 | var x = Float(a); | ||
| 2613 | return log(sqrt(x * x + 1) + x); | ||
| 2614 | } | ||
| 2615 | |||
| 2616 | function acosh(a) | ||
| 2617 | { | ||
| 2618 | var x = Float(a); | ||
| 2619 | return log(sqrt(x * x - 1) + x); | ||
| 2620 | } | ||
| 2621 | |||
| 2622 | function atanh(a) | ||
| 2623 | { | ||
| 2624 | var x = Float(a); | ||
| 2625 | return 0.5 * log((1 + x) / (1 - x)); | ||
| 2626 | } | ||
| 2627 | |||
| 2429 | var idn = Matrix.idn; | 2628 | var idn = Matrix.idn; |
| 2430 | var diag = Matrix.diag; | 2629 | var diag = Matrix.diag; |
| 2431 | var trans = Matrix.trans; | 2630 | var trans = Matrix.trans; |
| @@ -219,6 +219,8 @@ DEF(BigInt, "BigInt") · 218 unmodified lines | |||
| 219 | DEF(BigFloat, "BigFloat") | 219 | DEF(BigFloat, "BigFloat") |
| 220 | DEF(BigFloatEnv, "BigFloatEnv") | 220 | DEF(BigFloatEnv, "BigFloatEnv") |
| 221 | DEF(BigDecimal, "BigDecimal") | 221 | DEF(BigDecimal, "BigDecimal") |
| 222 | DEF(OperatorSet, "OperatorSet") | ||
| 223 | DEF(Operators, "Operators") | ||
| 222 | #endif | 224 | #endif |
| 223 | DEF(Map, "Map") | 225 | DEF(Map, "Map") |
| 224 | DEF(Set, "Set") /* Map + 1 */ | 226 | DEF(Set, "Set") /* Map + 1 */ |
| @@ -263,27 +265,7 @@ DEF(Symbol_species, "Symbol.species") · 38 unmodified lines | |||
| 263 | DEF(Symbol_unscopables, "Symbol.unscopables") | 265 | DEF(Symbol_unscopables, "Symbol.unscopables") |
| 264 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") | 266 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") |
| 265 | #ifdef CONFIG_BIGNUM | 267 | #ifdef CONFIG_BIGNUM |
| 266 | DEF(Symbol_operatorOrder, "Symbol.operatorOrder") | 268 | DEF(Symbol_operatorSet, "Symbol.operatorSet") |
| 267 | DEF(Symbol_operatorAdd, "Symbol.operatorAdd") | ||
| 268 | DEF(Symbol_operatorSub, "Symbol.operatorSub") | ||
| 269 | DEF(Symbol_operatorMul, "Symbol.operatorMul") | ||
| 270 | DEF(Symbol_operatorDiv, "Symbol.operatorDiv") | ||
| 271 | DEF(Symbol_operatorMod, "Symbol.operatorMod") | ||
| 272 | DEF(Symbol_operatorPow, "Symbol.operatorPow") | ||
| 273 | DEF(Symbol_operatorShl, "Symbol.operatorShl") | ||
| 274 | DEF(Symbol_operatorShr, "Symbol.operatorShr") | ||
| 275 | DEF(Symbol_operatorAnd, "Symbol.operatorAnd") | ||
| 276 | DEF(Symbol_operatorOr, "Symbol.operatorOr") | ||
| 277 | DEF(Symbol_operatorXor, "Symbol.operatorXor") | ||
| 278 | DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT") | ||
| 279 | DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE") | ||
| 280 | DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ") | ||
| 281 | DEF(Symbol_operatorPlus, "Symbol.operatorPlus") | ||
| 282 | DEF(Symbol_operatorNeg, "Symbol.operatorNeg") | ||
| 283 | DEF(Symbol_operatorNot, "Symbol.operatorNot") | ||
| 284 | DEF(Symbol_operatorInc, "Symbol.operatorInc") | ||
| 285 | DEF(Symbol_operatorDec, "Symbol.operatorDec") | ||
| 286 | DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod") | ||
| 287 | #endif | 269 | #endif |
| 288 | 270 | ||
| 289 | #endif /* DEF */ | 271 | #endif /* DEF */ |
| @@ -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 | ||
| 2030 | static 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] */ |
| 2031 | static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, | 2045 | static 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 ), |
| @@ -260,9 +260,7 @@ DEF( or, 1, 2, 1, none) · 259 unmodified lines | |||
| 260 | DEF(is_undefined_or_null, 1, 1, 1, none) | 260 | DEF(is_undefined_or_null, 1, 1, 1, none) |
| 261 | #ifdef CONFIG_BIGNUM | 261 | #ifdef CONFIG_BIGNUM |
| 262 | DEF( mul_pow10, 1, 2, 1, none) | 262 | DEF( mul_pow10, 1, 2, 1, none) |
| 263 | DEF( math_div, 1, 2, 1, none) | ||
| 264 | DEF( math_mod, 1, 2, 1, none) | 263 | DEF( math_mod, 1, 2, 1, none) |
| 265 | DEF( math_pow, 1, 2, 1, none) | ||
| 266 | #endif | 264 | #endif |
| 267 | /* must be the last non short and non temporary opcode */ | 265 | /* must be the last non short and non temporary opcode */ |
| 268 | DEF( nop, 1, 0, 0, none) | 266 | DEF( nop, 1, 0, 0, none) |
| @@ -271,7 +269,6 @@ DEF( nop, 1, 0, 0, none) · 2 unmodified lines | |||
| 271 | 269 | ||
| 272 | def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */ | 270 | def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */ |
| 273 | 271 | ||
| 274 | def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */ | ||
| 275 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ | 272 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ |
| 276 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ | 273 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ |
| 277 | 274 | ||
| @@ -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_BIGNUM | 45 | #ifdef CONFIG_BIGNUM |
| 50 | #include "libbf.h" | 46 | #include "libbf.h" |
| 51 | #endif | 47 | #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 | #endif | 152 | #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 | #endif | 286 | #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 | ||
| 306 | typedef struct JSStackFrame { | 303 | typedef 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 the | 309 | 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 if | 313 | /* 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_BIGNUM | 416 | #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 operator | 419 | BOOL bignum_ext : 8; /* enable math mode */ |
| 423 | overloading */ | 420 | BOOL allow_operator_overloading : 8; |
| 424 | #endif | 421 | #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 | ||
| 653 | typedef 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 | |||
| 681 | typedef struct { | ||
| 682 | uint32_t operator_index; | ||
| 683 | JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */ | ||
| 684 | } JSBinaryOperatorDefEntry; | ||
| 685 | |||
| 686 | typedef struct { | ||
| 687 | int count; | ||
| 688 | JSBinaryOperatorDefEntry *tab; | ||
| 689 | } JSBinaryOperatorDef; | ||
| 690 | |||
| 691 | typedef 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 | |||
| 656 | typedef struct JSReqModuleEntry { | 700 | typedef 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_BIGNUM | 853 | #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 | #endif | 856 | #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 | |||
| 991 | static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val); | 1036 | static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val); |
| 992 | static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, | 1037 | static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, |
| 993 | JS_MarkFunc *mark_func); | 1038 | JS_MarkFunc *mark_func); |
| 1039 | #ifdef CONFIG_BIGNUM | ||
| 1040 | static void js_operator_set_finalizer(JSRuntime *rt, JSValue val); | ||
| 1041 | static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, | ||
| 1042 | JS_MarkFunc *mark_func); | ||
| 1043 | #endif | ||
| 994 | static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); | 1044 | static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); |
| 995 | static int JS_ToBoolFree(JSContext *ctx, JSValue val); | 1045 | static int JS_ToBoolFree(JSContext *ctx, JSValue val); |
| 996 | static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); | 1046 | static 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_BIGNUM | 1072 | #ifdef CONFIG_BIGNUM |
| 1023 | static void js_float_env_finalizer(JSRuntime *rt, JSValue val); | 1073 | static void js_float_env_finalizer(JSRuntime *rt, JSValue val); |
| 1024 | static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a); | 1074 | static JSValue JS_NewBigFloat(JSContext *ctx); |
| 1025 | static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a); | 1075 | static inline bf_t *JS_GetBigFloat(JSValueConst val) |
| 1026 | static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint); | 1076 | { |
| 1027 | static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a); | 1077 | JSBigFloat *p = JS_VALUE_GET_PTR(val); |
| 1078 | return &p->num; | ||
| 1079 | } | ||
| 1080 | static JSValue JS_NewBigDecimal(JSContext *ctx); | ||
| 1081 | static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) | ||
| 1082 | { | ||
| 1083 | JSBigDecimal *p = JS_VALUE_GET_PTR(val); | ||
| 1084 | return &p->num; | ||
| 1085 | } | ||
| 1086 | static JSValue JS_NewBigInt(JSContext *ctx); | ||
| 1087 | static inline bf_t *JS_GetBigInt(JSValueConst val) | ||
| 1088 | { | ||
| 1089 | JSBigFloat *p = JS_VALUE_GET_PTR(val); | ||
| 1090 | return &p->num; | ||
| 1091 | } | ||
| 1092 | static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, | ||
| 1093 | BOOL convert_to_safe_integer); | ||
| 1094 | static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); | ||
| 1028 | static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); | 1095 | static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); |
| 1029 | static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); | 1096 | static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); |
| 1030 | static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); | 1097 | static 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 | |||
| 1123 | static const JSClassExoticMethods js_module_ns_exotic_methods; | 1190 | static const JSClassExoticMethods js_module_ns_exotic_methods; |
| 1124 | static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; | 1191 | static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; |
| 1125 | 1192 | ||
| 1126 | JS_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 | |||
| 1139 | static void js_trigger_gc(JSRuntime *rt, size_t size) | 1193 | static 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 | #endif | 1391 | #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_BIGNUM | 2193 | #ifdef CONFIG_BIGNUM |
| 2139 | static inline BOOL is_bigint_mode(JSContext *ctx) | 2194 | static 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 | #endif | 2199 | #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_BIGNUM | 2206 | 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 | ||
| 2165 | static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) | 2210 | static 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_BIGNUM | 5761 | #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 | #endif | 5765 | #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 | #else | 6566 | #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 an | 7786 | /* 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 0 | 9379 | #define HINT_STRING 0 |
| 9353 | #define HINT_NUMBER 1 | 9380 | #define HINT_NUMBER 1 |
| 9354 | #define HINT_NONE 2 | 9381 | #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 | ||
| 9617 | static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, | 9641 | static 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 | ||
| 9639 | static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, | 9667 | static 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 | #endif | 9687 | #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_BIGNUM | 9764 | #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 | } else | 9772 | } else |
| 9738 | #endif | 9773 | #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 | ||
| 9902 | typedef enum JSToNumberHintEnum { | 9937 | typedef 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 | #endif | 9973 | #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_BIGNUM | 9987 | 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 | ||
| 10005 | static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) | 10035 | static 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 | ||
| 10016 | static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, | 10045 | static __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 */ | ||
| 10081 | static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) | 10111 | static __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_BIGNUM | 10138 | #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 | else | 10149 | 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 | #endif | 10165 | #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_BIGNUM | 10208 | #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 | #endif | 10216 | #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_BIGNUM | 10282 | #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 | #endif | 10290 | #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_BIGNUM | 10362 | #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 | #endif | 10370 | #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_BIGNUM | 10429 | #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 | #endif | 10437 | #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_BIGNUM | 10493 | #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 | #endif | 10506 | #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 | ||
| 10580 | static BOOL is_safe_integer(double d) | ||
| 10581 | { | ||
| 10582 | return isfinite(d) && floor(d) == d && | ||
| 10583 | fabs(d) <= (double)MAX_SAFE_INTEGER; | ||
| 10584 | } | ||
| 10585 | |||
| 10587 | int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val) | 10586 | int 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 */ | ||
| 10613 | static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val) | 10611 | static 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 | ||
| 10756 | static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) | 10754 | static 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 | ||
| 10775 | static 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_BIGNUM | 11483 | #ifdef CONFIG_BIGNUM |
| 11480 | 11484 | ||
| 11485 | JSValue 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 | |||
| 11481 | JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) | 11500 | JSValue 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 | ||
| 11494 | JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) | 11510 | JSValue 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 to | 11529 | /* 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 | |||
| 11745 | static JSBigFloat *js_new_bf(JSContext *ctx) | 11768 | static 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 */ | 11779 | static JSValue JS_NewBigFloat(JSContext *ctx) |
| 11757 | static 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 */ | 11790 | static JSValue JS_NewBigDecimal(JSContext *ctx) |
| 11769 | static 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 */ | 11801 | static JSValue JS_NewBigInt(JSContext *ctx) |
| 11785 | static 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 | ||
| 11806 | static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a) | 11812 | static 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 overloading | 11833 | /* 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 |
| 11813 | static __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, | 11837 | static 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; | 11843 | static 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; | 11865 | static 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 */ | ||
| 11915 | static 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 */ | ||
| 11931 | static __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 */ | ||
| 12060 | static __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 */ | ||
| 12117 | static __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 | |||
| 11993 | static int js_unary_arith_bigint(JSContext *ctx, | 12179 | static 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 | ||
| 12038 | static int js_unary_arith_bigfloat(JSContext *ctx, | 12231 | static 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 | ||
| 12081 | static int js_unary_arith_bigdecimal(JSContext *ctx, | 12280 | static 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 | ||
| 12256 | static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) | 12442 | static 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 | |||
| 12297 | static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, | 12477 | static 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 | ||
| 12359 | static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, | 12538 | static 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 | |||
| 12536 | static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, | 12720 | static 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 | ||
| 13434 | static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) | 13606 | static 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 == 32 | 13622 | if (JS_IsBigInt(ctx, op2)) { |
| 13447 | ret = JS_ToInt32(ctx, &e, op2); | 13623 | ret = JS_ToBigInt64(ctx, &e, op2); |
| 13448 | #else | 13624 | } else { |
| 13449 | ret = JS_ToInt64(ctx, &e, op2); | 13625 | ret = JS_ToInt64(ctx, &e, op2); |
| 13450 | #endif | 13626 | } |
| 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_BIGNUM | 14061 | 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_INT | 14071 | } 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_BIGNUM | 14256 | #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 | #else | 14266 | #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 functions | 15432 | /* 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 | else | 15436 | else |
| 15293 | sf->js_mode = 0; | 15437 | sf->js_mode = 0; |
| 15294 | #else | 15438 | #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_BIGNUM | 17511 | #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_BIGNUM | 17688 | #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_BIGNUM | 17745 | #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 | else | 17749 | 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_BIGNUM | 20311 | #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 | } else | 23440 | } else |
| 23313 | #ifdef CONFIG_BIGNUM | 23441 | #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 | #else | 24237 | #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_BIGNUM | 24278 | 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_BIGNUM | 24281 | #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_BIGNUM | 24669 | #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 | #endif | 24674 | #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 separate | 30268 | /* line number info (for debug). We put it in a separate |
| 30168 | compressed table to reduce memory usage and get better | 30269 | 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 | #endif | 31610 | #endif |
| 31510 | #ifdef CONFIG_BIGNUM | 31611 | #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 | #endif | 31615 | #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_BIGNUM | 34490 | #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 | #else | 34500 | #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 | else | 35079 | } 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 | ||
| 35004 | static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val, | 35086 | static 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 | |||
| 37760 | static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val, | 37833 | static 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 | ||
| 37800 | static const JSCFunctionListEntry js_number_funcs[] = { | 37871 | static 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 | ||
| 37912 | static 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 | |||
| 37841 | static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val, | 37924 | static 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 | |||
| 39743 | enum { | ||
| 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 | |||
| 39771 | static 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 | |||
| 39862 | static 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 | |||
| 39931 | static 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 | |||
| 40013 | static 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 */ | ||
| 40053 | static 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 | |||
| 40083 | static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, | 39817 | static 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 | |||
| 40138 | static double js_math_sign(double a) | 39870 | static 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 | |||
| 40267 | static const JSCFunctionListEntry js_math_funcs[] = { | 39999 | static 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 | ||
| 42172 | static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v); | ||
| 42173 | #endif | ||
| 42174 | |||
| 42175 | static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, | 41865 | static 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 | ||
| 46866 | done: | 46568 | done: |
| @@ -47080,61 +46782,364 @@ void JS_AddIntrinsicEval(JSContext *ctx) · 213 unmodified lines | |||
| 47080 | 46782 | ||
| 47081 | #ifdef CONFIG_BIGNUM | 46783 | #ifdef CONFIG_BIGNUM |
| 47082 | 46784 | ||
| 46785 | /* Operators */ | ||
| 46786 | |||
| 46787 | static 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 | |||
| 46818 | static 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 */ | ||
| 46852 | static 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 | |||
| 46958 | static 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 | |||
| 46964 | static 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 | |||
| 47007 | static 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 | |||
| 47022 | static 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 | |||
| 47028 | static 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 | |||
| 47056 | static 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 */ | ||
| 47062 | void 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 | ||
| 47085 | static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) | 47085 | static 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 | ||
| 47157 | static 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 | |||
| 47168 | static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) | 47162 | static 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 | ||
| 47259 | static JSValue js_bigint_sqrt(JSContext *ctx, | 47259 | static 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 | ||
| 47291 | static JSValue js_bigint_op1(JSContext *ctx, | 47304 | static 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 | ||
| 47357 | static const JSCFunctionListEntry js_bigint_funcs[] = { | 47377 | static 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 | ||
| 47454 | static int get_rnd_mode(JSContext *ctx, JSValueConst val) | 47471 | static 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 | ||
| 47704 | static JSValue js_bigfloat_get_const(JSContext *ctx, | 47745 | static 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 | ||
| 47747 | static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val, | 47792 | static 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 | |||
| 47854 | enum { | ||
| 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 | |||
| 47882 | static 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 | |||
| 47976 | static 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 | ||
| 47806 | static const JSCFunctionListEntry js_bigfloat_funcs[] = { | 48048 | static 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 | |||
| 47901 | static JSValue js_float_env_setPrec(JSContext *ctx, | 48140 | static 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 | ||
| 48042 | static const JSCFunctionListEntry js_float_env_proto_funcs[] = { | 48275 | static 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 | ||
| 48480 | static 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 | |||
| 48233 | typedef struct { | 48513 | typedef 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 | |||
| 48669 | static 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 | |||
| 48699 | static 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 | |||
| 48735 | static 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 | ||
| 48408 | static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = { | 48769 | static 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 | ||
| 48413 | static const JSCFunctionListEntry js_bigdecimal_funcs[] = { | 48777 | static 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: |
| @@ -53,7 +53,7 @@ typedef struct JSClass JSClass; · 52 unmodified lines | |||
| 53 | typedef uint32_t JSClassID; | 53 | typedef uint32_t JSClassID; |
| 54 | typedef uint32_t JSAtom; | 54 | typedef uint32_t JSAtom; |
| 55 | 55 | ||
| 56 | #if defined(__x86_64__) || defined(__aarch64__) | 56 | #if INTPTR_MAX >= INT64_MAX |
| 57 | #define JS_PTR64 | 57 | #define JS_PTR64 |
| 58 | #define JS_PTR64_DEF(a) a | 58 | #define JS_PTR64_DEF(a) a |
| 59 | #else | 59 | #else |
| @@ -366,7 +366,9 @@ void JS_AddIntrinsicPromise(JSContext *ctx); · 306 unmodified lines | |||
| 366 | void JS_AddIntrinsicBigInt(JSContext *ctx); | 366 | void JS_AddIntrinsicBigInt(JSContext *ctx); |
| 367 | void JS_AddIntrinsicBigFloat(JSContext *ctx); | 367 | void JS_AddIntrinsicBigFloat(JSContext *ctx); |
| 368 | void JS_AddIntrinsicBigDecimal(JSContext *ctx); | 368 | void JS_AddIntrinsicBigDecimal(JSContext *ctx); |
| 369 | /* enable "use bigint", "use math" and operator overloading */ | 369 | /* enable operator overloading */ |
| 370 | void JS_AddIntrinsicOperators(JSContext *ctx); | ||
| 371 | /* enable "use math" */ | ||
| 370 | void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); | 372 | void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); |
| 371 | 373 | ||
| 372 | JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, | 374 | JSValue 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 | ||
| 534 | JS_BOOL JS_IsNumber(JSValueConst v); | 536 | static 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 | ||
| 536 | static inline JS_BOOL JS_IsInteger(JSValueConst v) | 542 | static 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 | ||
| 542 | static inline JS_BOOL JS_IsBigFloat(JSValueConst v) | 548 | static inline JS_BOOL JS_IsBigFloat(JSValueConst v) |
| @@ -1,8 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * QuickJS Read Eval Print Loop | 2 | * QuickJS Read Eval Print Loop |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2017-2019 Fabrice Bellard | 4 | * Copyright (c) 2017-2020 Fabrice Bellard |
| 5 | * Copyright (c) 2017-2019 Charlie Gordon | 5 | * Copyright (c) 2017-2020 Charlie Gordon |
| 6 | * | 6 | * |
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | * of this software and associated documentation files (the "Software"), to deal | 8 | * 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 }); |
| @@ -1,4 +1,17 @@ | |||
| 1 | test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 2 | test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 3 | test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 4 | test262/test/language/expressions/class/super-evaluation-order.js:26: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true | ||
| 5 | test262/test/language/expressions/class/super-evaluation-order.js:26: strict mode: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true | ||
| 1 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called | 6 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called |
| 2 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called | 7 | test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called |
| 8 | test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 9 | test262/test/language/expressions/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 10 | test262/test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:32: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 11 | test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 12 | test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 3 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property | 13 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property |
| 4 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property | 14 | test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property |
| 15 | test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 16 | test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| 17 | test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all | ||
| @@ -171,67 +171,152 @@ function test_bigfloat() · 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 | ||
| 182 | function test_bigdecimal() | 238 | function 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 | ||
| 237 | test_bigint1(); | 322 | test_bigint1(); |
| @@ -0,0 +1,207 @@ | |||
| 1 | "use strict"; | ||
| 2 | |||
| 3 | function 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() */ | ||
| 21 | function 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 */ | ||
| 108 | function 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 | |||
| 198 | function test_default_op() | ||
| 199 | { | ||
| 200 | assert(Object(1) + 2, 3); | ||
| 201 | assert(Object(1) + true, 2); | ||
| 202 | assert(-Object(1), -1); | ||
| 203 | } | ||
| 204 | |||
| 205 | test_operators_create(); | ||
| 206 | test_operators(); | ||
| 207 | test_default_op(); | ||
| @@ -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 | ||
| 71 | function test_float() | 75 | function 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 | ||
| 105 | function 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 | |||
| 104 | function test_mod() | 115 | function test_mod() |
| 105 | { | 116 | { |
| 106 | var a, b, p; | 117 | var a, b, p; |
| @@ -235,6 +246,7 @@ test_integer(); · 128 unmodified lines | |||
| 235 | test_float(); | 246 | test_float(); |
| 236 | 247 | ||
| 237 | test_modulo(); | 248 | test_modulo(); |
| 249 | test_fraction(); | ||
| 238 | test_mod(); | 250 | test_mod(); |
| 239 | test_polynomial(); | 251 | test_polynomial(); |
| 240 | test_poly_mod(); | 252 | test_poly_mod(); |