Remove BigFloat (#31)

Part of https://github.com/quickjs-ng/quickjs/issues/17
This commit is contained in:
Ben Noordhuis 2023-11-08 22:23:06 +01:00 committed by GitHub
parent c1ed688610
commit e449cb08ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 72 additions and 1952 deletions

View file

@ -54,7 +54,7 @@ prefix=/usr/local
#CONFIG_MSAN=y
# use UB sanitizer
#CONFIG_UBSAN=y
# include the code for BigInt/BigFloat
# include the code for BigInt
CONFIG_BIGNUM=y
OBJDIR=.obj

View file

@ -1,66 +0,0 @@
/*
* PI computation in Javascript using the QuickJS bigfloat type
* (binary floating point)
*/
"use strict";
/* compute PI with a precision of 'prec' bits */
function calc_pi() {
const CHUD_A = 13591409n;
const CHUD_B = 545140134n;
const CHUD_C = 640320n;
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
/* return [P, Q, G] */
function chud_bs(a, b, need_G) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
if (a == (b - 1n)) {
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
P = BigFloat(G * (CHUD_B * b + CHUD_A));
if (b & 1n)
P = -P;
G = BigFloat(G);
Q = BigFloat(b * b * b * CHUD_C3);
} else {
c = (a + b) >> 1n;
[P1, Q1, G1] = chud_bs(a, c, true);
[P2, Q2, G2] = chud_bs(c, b, need_G);
P = P1 * Q2 + P2 * G1;
Q = Q1 * Q2;
if (need_G)
G = G1 * G2;
else
G = 0l;
}
return [P, Q, G];
}
var n, P, Q, G;
/* number of serie terms */
n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
[P, Q, G] = chud_bs(0n, n, false);
Q = Q / (P + Q * BigFloat(CHUD_A));
G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
return Q * G;
}
(function() {
var r, n_digits, n_bits;
if (typeof scriptArgs != "undefined") {
if (scriptArgs.length < 2) {
print("usage: pi n_digits");
return;
}
n_digits = scriptArgs[1];
} else {
n_digits = 1000;
}
n_bits = Math.ceil(n_digits * Math.log2(10));
/* we add more bits to reduce the probability of bad rounding for
the last digits */
BigFloatEnv.setPrec( () => {
r = calc_pi();
print(r.toFixed(n_digits, BigFloatEnv.RNDZ));
}, n_bits + 32);
})();

1
qjs.c
View file

@ -109,7 +109,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
return NULL;
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}

2
qjsc.c
View file

@ -633,7 +633,6 @@ int main(int argc, char **argv)
ctx = JS_NewContext(rt);
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
@ -689,7 +688,6 @@ int main(int argc, char **argv)
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
fprintf(fo,
" JS_AddIntrinsicBigFloat(ctx);\n"
" JS_AddIntrinsicOperators(ctx);\n"
" JS_EnableBignumExt(ctx, 1);\n");
}

View file

@ -171,11 +171,6 @@ DEF(reason, "reason")
DEF(globalThis, "globalThis")
#ifdef CONFIG_BIGNUM
DEF(bigint, "bigint")
DEF(bigfloat, "bigfloat")
DEF(bigdecimal, "bigdecimal")
DEF(roundingMode, "roundingMode")
DEF(maximumSignificantDigits, "maximumSignificantDigits")
DEF(maximumFractionDigits, "maximumFractionDigits")
#endif
#ifdef CONFIG_ATOMICS
DEF(not_equal, "not-equal")
@ -218,8 +213,6 @@ DEF(Float64Array, "Float64Array")
DEF(DataView, "DataView")
#ifdef CONFIG_BIGNUM
DEF(BigInt, "BigInt")
DEF(BigFloat, "BigFloat")
DEF(BigFloatEnv, "BigFloatEnv")
DEF(OperatorSet, "OperatorSet")
DEF(Operators, "Operators")
#endif

View file

@ -256,9 +256,6 @@ DEF( and, 1, 2, 1, none)
DEF( xor, 1, 2, 1, none)
DEF( or, 1, 2, 1, none)
DEF(is_undefined_or_null, 1, 1, 1, none)
#ifdef CONFIG_BIGNUM
DEF( mul_pow10, 1, 2, 1, none)
#endif
/* must be the last non short and non temporary opcode */
DEF( nop, 1, 0, 0, none)

1568
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -66,9 +66,8 @@ typedef uint32_t JSAtom;
enum {
/* all tags with a reference count are negative */
JS_TAG_FIRST = -10, /* first negative tag */
JS_TAG_BIG_INT = -10,
JS_TAG_BIG_FLOAT = -9,
JS_TAG_FIRST = -9, /* first negative tag */
JS_TAG_BIG_INT = -9,
JS_TAG_SYMBOL = -8,
JS_TAG_STRING = -7,
JS_TAG_MODULE = -3, /* used internally */
@ -370,7 +369,6 @@ void JS_AddIntrinsicMapSet(JSContext *ctx);
void JS_AddIntrinsicTypedArrays(JSContext *ctx);
void JS_AddIntrinsicPromise(JSContext *ctx);
void JS_AddIntrinsicBigInt(JSContext *ctx);
void JS_AddIntrinsicBigFloat(JSContext *ctx);
/* enable operator overloading */
void JS_AddIntrinsicOperators(JSContext *ctx);
/* enable "use math" */
@ -553,12 +551,6 @@ static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
return tag == JS_TAG_BIG_INT;
}
static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
{
int tag = JS_VALUE_GET_TAG(v);
return tag == JS_TAG_BIG_FLOAT;
}
static inline JS_BOOL JS_IsBool(JSValueConst v)
{
return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;

238
repl.js
View file

@ -39,11 +39,6 @@ import * as os from "os";
var isFinite = g.isFinite;
var parseFloat = g.parseFloat;
/* XXX: use preprocessor ? */
var config_numcalc = (typeof os.open === "undefined");
var has_jscalc = (typeof Fraction === "function");
var has_bignum = (typeof BigFloat === "function");
var colors = {
none: "\x1b[0m",
black: "\x1b[30m",
@ -65,38 +60,20 @@ import * as os from "os";
bright_white: "\x1b[37;1m",
};
var styles;
if (config_numcalc) {
styles = {
'default': 'black',
'comment': 'white',
'string': 'green',
'regex': 'cyan',
'number': 'green',
'keyword': 'blue',
'function': 'gray',
'type': 'bright_magenta',
'identifier': 'yellow',
'error': 'bright_red',
'result': 'black',
'error_msg': 'bright_red',
};
} else {
styles = {
'default': 'bright_green',
'comment': 'white',
'string': 'bright_cyan',
'regex': 'cyan',
'number': 'green',
'keyword': 'bright_white',
'function': 'bright_yellow',
'type': 'bright_magenta',
'identifier': 'bright_green',
'error': 'red',
'result': 'bright_white',
'error_msg': 'bright_red',
};
}
var styles = {
'default': 'bright_green',
'comment': 'white',
'string': 'bright_cyan',
'regex': 'cyan',
'number': 'green',
'keyword': 'bright_white',
'function': 'bright_yellow',
'type': 'bright_magenta',
'identifier': 'bright_green',
'error': 'red',
'result': 'bright_white',
'error_msg': 'bright_red',
};
var history = [];
var clip_board = "";
@ -107,11 +84,7 @@ import * as os from "os";
var pstate = "";
var prompt = "";
var plen = 0;
var ps1;
if (config_numcalc)
ps1 = "> ";
else
ps1 = "qjs > ";
var ps1 = "qjs > ";
var ps2 = " ... ";
var utf8 = true;
var show_time = false;
@ -931,48 +904,6 @@ import * as os from "os";
}
}
function bigfloat_to_string(a, radix) {
var s;
if (!BigFloat.isFinite(a)) {
/* NaN, Infinite */
if (eval_mode !== "math") {
return "BigFloat(" + a.toString() + ")";
} else {
return a.toString();
}
} else {
if (a == 0) {
if (1 / a < 0)
s = "-0";
else
s = "0";
} else {
if (radix == 16) {
var s;
if (a < 0) {
a = -a;
s = "-";
} else {
s = "";
}
s += "0x" + a.toString(16);
} else {
s = a.toString();
}
}
if (typeof a === "bigfloat" && eval_mode !== "math") {
s += "l";
} else if (eval_mode !== "std" && s.indexOf(".") < 0 &&
((radix == 16 && s.indexOf("p") < 0) ||
(radix == 10 && s.indexOf("e") < 0))) {
/* add a decimal point so that the floating point type
is visible */
s += ".0";
}
return s;
}
}
function bigint_to_string(a, radix) {
var s;
if (radix == 16) {
@ -1004,14 +935,6 @@ import * as os from "os";
std.puts(a);
} else if (stack.indexOf(a) >= 0) {
std.puts("[circular]");
} else if (has_jscalc && (a instanceof Fraction ||
a instanceof Complex ||
a instanceof Mod ||
a instanceof Polynomial ||
a instanceof PolyMod ||
a instanceof RationalFunction ||
a instanceof Series)) {
std.puts(a.toString());
} else {
stack.push(a);
if (Array.isArray(a)) {
@ -1057,10 +980,6 @@ import * as os from "os";
std.puts(number_to_string(a, hex_mode ? 16 : 10));
} else if (type === "bigint") {
std.puts(bigint_to_string(a, hex_mode ? 16 : 10));
} else if (type === "bigfloat") {
std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
} else if (type === "bigdecimal") {
std.puts(a.toString() + "m");
} else if (type === "symbol") {
std.puts(String(a));
} else if (type === "function") {
@ -1101,75 +1020,10 @@ import * as os from "os";
hex_mode = false;
} else if (cmd === "t") {
show_time = !show_time;
} else if (has_bignum && cmd === "p") {
param = expr.substring(cmd.length + 1).trim().split(" ");
if (param.length === 1 && param[0] === "") {
std.puts("BigFloat precision=" + prec + " bits (~" +
Math.floor(prec / log2_10) +
" digits), exponent size=" + expBits + " bits\n");
} else if (param[0] === "f16") {
prec = 11;
expBits = 5;
} else if (param[0] === "f32") {
prec = 24;
expBits = 8;
} else if (param[0] === "f64") {
prec = 53;
expBits = 11;
} else if (param[0] === "f128") {
prec = 113;
expBits = 15;
} else {
prec1 = parseInt(param[0]);
if (param.length >= 2)
expBits1 = parseInt(param[1]);
else
expBits1 = BigFloatEnv.expBitsMax;
if (Number.isNaN(prec1) ||
prec1 < BigFloatEnv.precMin ||
prec1 > BigFloatEnv.precMax) {
std.puts("Invalid precision\n");
return false;
}
if (Number.isNaN(expBits1) ||
expBits1 < BigFloatEnv.expBitsMin ||
expBits1 > BigFloatEnv.expBitsMax) {
std.puts("Invalid exponent bits\n");
return false;
}
prec = prec1;
expBits = expBits1;
}
return false;
} else if (has_bignum && cmd === "digits") {
param = expr.substring(cmd.length + 1).trim();
prec1 = Math.ceil(parseFloat(param) * log2_10);
if (prec1 < BigFloatEnv.precMin ||
prec1 > BigFloatEnv.precMax) {
std.puts("Invalid precision\n");
return false;
}
prec = prec1;
expBits = BigFloatEnv.expBitsMax;
return false;
} else if (has_bignum && cmd === "mode") {
param = expr.substring(cmd.length + 1).trim();
if (param === "") {
std.puts("Running mode=" + eval_mode + "\n");
} else if (param === "std" || param === "math") {
eval_mode = param;
} else {
std.puts("Invalid mode\n");
}
return false;
} else if (cmd === "clear") {
std.puts("\x1b[H\x1b[J");
} else if (cmd === "q") {
std.exit(0);
} else if (has_jscalc && cmd === "a") {
algebraicMode = true;
} else if (has_jscalc && cmd === "n") {
algebraicMode = false;
} else {
std.puts("Unknown directive: " + cmd + "\n");
return false;
@ -1177,26 +1031,6 @@ import * as os from "os";
return true;
}
if (config_numcalc) {
/* called by the GUI */
g.execCmd = function (cmd) {
switch(cmd) {
case "dec":
hex_mode = false;
break;
case "hex":
hex_mode = true;
break;
case "num":
algebraicMode = false;
break;
case "alg":
algebraicMode = true;
break;
}
}
}
function help() {
function sel(n) {
return n ? "*": " ";
@ -1205,21 +1039,8 @@ import * as os from "os";
"\\x " + sel(hex_mode) + "hexadecimal number display\n" +
"\\d " + sel(!hex_mode) + "decimal number display\n" +
"\\t " + sel(show_time) + "toggle timing display\n" +
"\\clear clear the terminal\n");
if (has_jscalc) {
std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" +
"\\n " + sel(!algebraicMode) + "numeric mode\n");
}
if (has_bignum) {
std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
"\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
if (!has_jscalc) {
std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
}
}
if (!config_numcalc) {
std.puts("\\q exit\n");
}
"\\clear clear the terminal\n" +
"\\q exit\n");
}
function eval_and_print(expr) {
@ -1254,23 +1075,7 @@ import * as os from "os";
}
function cmd_start() {
if (!config_numcalc) {
if (has_jscalc)
std.puts('QJSCalc - Type "\\h" for help\n');
else
std.puts('QuickJS - Type "\\h" for help\n');
}
if (has_bignum) {
log2_10 = Math.log(10) / Math.log(2);
prec = 113;
expBits = 15;
if (has_jscalc) {
eval_mode = "math";
/* XXX: numeric mode should always be the default ? */
g.algebraicMode = config_numcalc;
}
}
std.puts('QuickJS - Type "\\h" for help\n');
cmd_readline_start();
}
@ -1314,12 +1119,7 @@ import * as os from "os";
}
mexpr = "";
if (has_bignum) {
BigFloatEnv.setPrec(eval_and_print.bind(null, expr),
prec, expBits);
} else {
eval_and_print(expr);
}
eval_and_print(expr);
level = 0;
/* run the garbage collector after each command */

View file

@ -559,29 +559,6 @@ function float_arith(n)
return n * 1000;
}
function bigfloat_arith(n)
{
var i, j, sum, a, incr, a0;
global_res = 0;
a0 = BigFloat("0.1");
incr = BigFloat("1.1");
for(j = 0; j < n; j++) {
sum = 0;
a = a0;
for(i = 0; i < 1000; i++) {
sum += a * a;
a += incr;
}
global_res += sum;
}
return n * 1000;
}
function float256_arith(n)
{
return BigFloatEnv.setPrec(bigfloat_arith.bind(null, n), 237, 19);
}
function bigint_arith(n, bits)
{
var i, j, sum, a, incr, a0, sum0;
@ -1001,10 +978,6 @@ function main(argc, argv, g)
test_list.push(bigint64_arith);
test_list.push(bigint256_arith);
}
if (typeof BigFloat == "function") {
/* BigFloat test */
test_list.push(float256_arith);
}
for (i = 1; i < argc;) {
name = argv[i++];

View file

@ -147,95 +147,6 @@ function test_bigint_ext()
test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]);
}
function test_bigfloat()
{
var e, a, b, sqrt2;
assert(typeof 1n === "bigint");
assert(typeof 1l === "bigfloat");
assert(1 == 1.0l);
assert(1 !== 1.0l);
test_less(2l, 3l);
test_eq(3l, 3l);
test_less(2, 3l);
test_eq(3, 3l);
test_less(2.1, 3l);
test_eq(Math.sqrt(9), 3l);
test_less(2n, 3l);
test_eq(3n, 3l);
e = new BigFloatEnv(128);
assert(e.prec == 128);
a = BigFloat.sqrt(2l, e);
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
assert(e.inexact === true);
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
assert(a === b);
assert(BigFloat.isNaN(BigFloat(NaN)));
assert(BigFloat.isFinite(1l));
assert(!BigFloat.isFinite(1l/0l));
assert(BigFloat.abs(-3l) === 3l);
assert(BigFloat.sign(-3l) === -1l);
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
assert(BigFloat.floor(2.5l) === 2l);
assert(BigFloat.ceil(2.5l) === 3l);
assert(BigFloat.trunc(-2.5l) === -2l);
assert(BigFloat.round(2.5l) === 3l);
assert(BigFloat.fmod(3l,2l) === 1l);
assert(BigFloat.remainder(3l,2l) === -1l);
/* string conversion */
assert((1234.125l).toString(), "1234.125");
assert((1234.125l).toFixed(2), "1234.13");
assert((1234.125l).toFixed(2, "down"), "1234.12");
assert((1234.125l).toExponential(), "1.234125e+3");
assert((1234.125l).toExponential(5), "1.23413e+3");
assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
assert((1234.125l).toPrecision(6), "1234.13");
assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
/* string conversion with binary base */
assert((0x123.438l).toString(16), "123.438");
assert((0x323.438l).toString(16), "323.438");
assert((0x723.438l).toString(16), "723.438");
assert((0xf23.438l).toString(16), "f23.438");
assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
}
test_bigint1();
test_bigint2();
test_bigint_ext();
test_bigfloat();

View file

@ -87,7 +87,6 @@ function toStr(a)
case "string":
return a.__quote();
case "number":
case "bigfloat":
if (a == 0 && 1 / a < 0)
return "-0";
else
@ -155,14 +154,6 @@ function bjson_test_all()
bjson_test([BigInt("1"), -BigInt("0x123456789"),
BigInt("0x123456789abcdef123456789abcdef")]);
}
if (typeof BigFloat !== "undefined") {
BigFloatEnv.setPrec(function () {
bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"),
BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"),
0.0 / BigFloat("0"), BigFloat.MAX_VALUE,
BigFloat.MIN_VALUE]);
}, 113, 15);
}
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);