Coverage Report

Created: 2026-01-29 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsNumber.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
static txSlot* fxCheckNumber(txMachine* the, txSlot* it);
41
42
void fxBuildNumber(txMachine* the)
43
21.1k
{
44
21.1k
  txSlot* slot;
45
  
46
21.1k
  mxPushNumber((txNumber)C_INFINITY);
47
21.1k
  mxPull(mxInfinity);
48
21.1k
  mxPushNumber((txNumber)C_NAN);
49
21.1k
  mxPull(mxNaN);
50
51
21.1k
  mxPush(mxObjectPrototype);
52
21.1k
  slot = fxLastProperty(the, fxNewNumberInstance(the));
53
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toExponential), 1, mxID(_toExponential), XS_DONT_ENUM_FLAG);
54
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toFixed), 1, mxID(_toFixed), XS_DONT_ENUM_FLAG);
55
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toLocaleString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
56
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toPrecision), 1, mxID(_toPrecision), XS_DONT_ENUM_FLAG);
57
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_toString), 1, mxID(_toString), XS_DONT_ENUM_FLAG);
58
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_prototype_valueOf), 0, mxID(_valueOf), XS_DONT_ENUM_FLAG);
59
21.1k
  mxNumberPrototype = *the->stack;
60
21.1k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Number), 1, mxID(_Number));
61
21.1k
  mxNumberConstructor = *the->stack;
62
21.1k
  slot = fxLastProperty(the, slot);
63
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isFinite), 1, mxID(_isFinite), XS_DONT_ENUM_FLAG);
64
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isInteger), 1, mxID(_isInteger), XS_DONT_ENUM_FLAG);
65
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isNaN), 1, mxID(_isNaN), XS_DONT_ENUM_FLAG);
66
21.1k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Number_isSafeInteger), 1, mxID(_isSafeInteger), XS_DONT_ENUM_FLAG);
67
21.1k
  slot = fxNextSlotProperty(the, slot, &mxParseFloatFunction, mxID(_parseFloat), XS_DONT_ENUM_FLAG);
68
21.1k
  slot = fxNextSlotProperty(the, slot, &mxParseIntFunction, mxID(_parseInt), XS_DONT_ENUM_FLAG);
69
21.1k
  slot = fxNextNumberProperty(the, slot, C_EPSILON, mxID(_EPSILON), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
70
21.1k
  slot = fxNextNumberProperty(the, slot, C_MAX_SAFE_INTEGER, mxID(_MAX_SAFE_INTEGER), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
71
21.1k
  slot = fxNextNumberProperty(the, slot, C_DBL_MAX, mxID(_MAX_VALUE), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
72
21.1k
  slot = fxNextNumberProperty(the, slot, C_MIN_SAFE_INTEGER, mxID(_MIN_SAFE_INTEGER), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
73
21.1k
  slot = fxNextNumberProperty(the, slot, C_DBL_MIN, mxID(_MIN_VALUE), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
74
21.1k
  slot = fxNextNumberProperty(the, slot, C_NAN, mxID(_NaN), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
75
21.1k
  slot = fxNextNumberProperty(the, slot, -((txNumber)C_INFINITY), mxID(_NEGATIVE_INFINITY), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
76
21.1k
  slot = fxNextNumberProperty(the, slot, (txNumber)C_INFINITY, mxID(_POSITIVE_INFINITY), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
77
21.1k
  mxPop();
78
21.1k
}
79
80
txSlot* fxNewNumberInstance(txMachine* the)
81
10.4M
{
82
10.4M
  txSlot* instance;
83
10.4M
  instance = fxNewObjectInstance(the);
84
10.4M
  fxNextNumberProperty(the, instance, 0, XS_NO_ID, XS_INTERNAL_FLAG);
85
10.4M
  return instance;
86
10.4M
}
87
88
void fxNumberCoerce(txMachine* the, txSlot* slot)
89
1.90k
{
90
1.90k
  fxToNumber(the, slot);
91
1.90k
}
92
93
void fx_isFinite(txMachine* the)
94
4.45k
{
95
4.45k
  int fpclass;
96
4.45k
  txNumber number = (mxArgc < 1) ?  C_NAN : fxToNumber(the, mxArgv(0)); 
97
4.45k
  mxResult->kind = XS_BOOLEAN_KIND;
98
4.45k
    mxResult->value.boolean = 0;
99
4.45k
  fpclass = c_fpclassify(number);
100
4.45k
  if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE))
101
3.13k
    mxResult->value.boolean = 1;
102
4.45k
}
103
104
void fx_isNaN(txMachine* the)
105
3.48k
{
106
3.48k
  int fpclass;
107
3.48k
  txNumber number = (mxArgc < 1) ?  C_NAN : fxToNumber(the, mxArgv(0)); 
108
3.48k
  mxResult->kind = XS_BOOLEAN_KIND;
109
3.48k
    mxResult->value.boolean = 0;
110
3.48k
  fpclass = c_fpclassify(number);
111
3.48k
  if (fpclass == C_FP_NAN)
112
2.18k
    mxResult->value.boolean = 1;
113
3.48k
}
114
115
void fx_parseFloat(txMachine* the)
116
41.3k
{
117
41.3k
  if (mxArgc < 1) {
118
128
    mxResult->value.number = C_NAN;
119
128
    mxResult->kind = XS_NUMBER_KIND;
120
128
        return;
121
128
  }
122
41.2k
  fxToString(the, mxArgv(0));
123
41.2k
  mxResult->kind = XS_NUMBER_KIND;
124
41.2k
  mxResult->value.number = fxStringToNumber(the, mxArgv(0)->value.string, 0);
125
41.2k
}
126
127
void fx_parseInt(txMachine* the)
128
1.06M
{
129
1.06M
  txInteger aRadix, aDigit;
130
1.06M
  txNumber aSign, aResult;
131
1.06M
  txString s, r;
132
1.06M
  char c;
133
  
134
1.06M
  if (mxArgc < 1) {
135
203
    mxResult->value.number = C_NAN;
136
203
    mxResult->kind = XS_NUMBER_KIND;
137
203
        return;
138
203
  }
139
1.06M
  fxToString(the, mxArgv(0));
140
1.06M
  if (mxArgc > 1) {
141
1.06M
    aRadix = fxToInteger(the, mxArgv(1));
142
1.06M
    if (aRadix) {
143
903k
      if ((aRadix < 2) || (36 < aRadix)) {
144
84.1k
        mxResult->kind = XS_NUMBER_KIND;
145
84.1k
        mxResult->value.number = C_NAN;
146
84.1k
        return;
147
84.1k
      }
148
903k
    }
149
1.06M
  }
150
3.41k
  else
151
3.41k
    aRadix = 0;
152
979k
  s = fxSkipSpaces(mxArgv(0)->value.string);
153
979k
  c = *s;
154
979k
  aSign = 1;
155
979k
  if (c == '+')
156
540
    s++;
157
978k
  else if (c == '-') {
158
2.00k
    s++;
159
2.00k
    aSign = -1;
160
2.00k
  }
161
979k
  if ((*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) {
162
291
    if ((aRadix == 0) || (aRadix == 16)) {
163
280
      aRadix = 16;
164
280
      s += 2;
165
280
    }
166
291
  }
167
  /*if (*s == '0') {
168
    if ((aRadix == 0) || (aRadix == 8)) {
169
      aRadix = 8;
170
    }
171
  }*/
172
979k
  if (aRadix == 0)
173
159k
    aRadix = 10;
174
979k
  aResult = 0;
175
979k
  r = s;
176
1.05M
  while ((c = *s)) {
177
182k
    if (('0' <= c) && (c <= '9'))
178
48.3k
      aDigit = c - '0';
179
133k
    else if (('a' <= c) && (c <= 'z'))
180
2.55k
      aDigit = 10 + c - 'a';
181
131k
    else if (('A' <= c) && (c <= 'Z'))
182
30.1k
      aDigit = 10 + c - 'A';
183
101k
    else
184
101k
      break;
185
81.0k
    if (aDigit >= aRadix)
186
2.16k
      break;
187
78.9k
    aResult = (aResult * aRadix) + aDigit;
188
78.9k
    s++;
189
78.9k
  }
190
979k
  if (r == s) {
191
948k
    mxResult->kind = XS_NUMBER_KIND;
192
948k
    mxResult->value.number = C_NAN;
193
948k
  }
194
30.5k
  else {
195
30.5k
    aResult *= aSign;
196
30.5k
    aRadix = (txInteger)aResult;
197
30.5k
    aSign = aRadix;
198
30.5k
    if (aSign == aResult) {
199
29.3k
      mxResult->value.integer = aRadix;
200
29.3k
      mxResult->kind = XS_INTEGER_KIND;
201
29.3k
    }
202
1.17k
    else {
203
1.17k
      mxResult->value.number = aResult;
204
1.17k
      mxResult->kind = XS_NUMBER_KIND;
205
1.17k
    }
206
30.5k
  }
207
979k
}
208
209
void fx_Number(txMachine* the)
210
245k
{
211
245k
  txNumber value = 0;
212
245k
  if (mxArgc > 0) {
213
132k
    txSlot* slot = mxArgv(0);
214
132k
    if (slot->kind == XS_REFERENCE_KIND)
215
1.59k
      fxToPrimitive(the, slot, XS_NUMBER_HINT);
216
132k
    if ((slot->kind == XS_BIGINT_KIND) || (slot->kind == XS_BIGINT_X_KIND))
217
414
      value = fxBigIntToNumber(the, slot);
218
131k
    else
219
131k
      value = fxToNumber(the, slot);
220
132k
  }
221
245k
  if (mxIsUndefined(mxTarget)) {
222
244k
        mxResult->kind = XS_NUMBER_KIND;
223
244k
        mxResult->value.number = value;
224
244k
        fx_Math_toInteger(the);
225
244k
  }
226
1.21k
  else {
227
1.21k
    txSlot* instance;
228
1.21k
    mxPushSlot(mxTarget);
229
1.21k
    fxGetPrototypeFromConstructor(the, &mxNumberPrototype);
230
1.21k
    instance = fxNewNumberInstance(the);
231
1.21k
    instance->next->value.number = value;
232
1.21k
    mxPullSlot(mxResult);
233
1.21k
  }
234
245k
}
235
236
void fx_Number_isFinite(txMachine* the)
237
66
{
238
66
  int fpclass;
239
66
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
240
66
  mxResult->kind = XS_BOOLEAN_KIND;
241
66
    mxResult->value.boolean = 0;
242
66
    if (slot) {
243
65
      if (slot->kind == XS_INTEGER_KIND)
244
19
      mxResult->value.boolean = 1;
245
46
      else if (slot->kind == XS_NUMBER_KIND) {
246
28
      fpclass = c_fpclassify(slot->value.number);
247
28
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE))
248
17
        mxResult->value.boolean = 1;
249
28
    }
250
65
  }
251
66
}
252
253
void fx_Number_isInteger(txMachine* the)
254
1.91k
{
255
1.91k
  int fpclass;
256
1.91k
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
257
1.91k
  mxResult->kind = XS_BOOLEAN_KIND;
258
1.91k
    mxResult->value.boolean = 0;
259
1.91k
    if (slot) {
260
1.91k
      if (slot->kind == XS_INTEGER_KIND)
261
1.87k
      mxResult->value.boolean = 1;
262
41
      else if (slot->kind == XS_NUMBER_KIND) {
263
23
      fpclass = c_fpclassify(slot->value.number);
264
23
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) {
265
19
        txNumber check = c_trunc(slot->value.number);
266
19
        if (slot->value.number == check)
267
11
          mxResult->value.boolean = 1;
268
19
      }
269
23
    }
270
1.91k
  }
271
1.91k
}
272
273
void fx_Number_isNaN(txMachine* the)
274
43
{
275
43
  int fpclass;
276
43
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
277
43
  mxResult->kind = XS_BOOLEAN_KIND;
278
43
    mxResult->value.boolean = 0;
279
43
    if (slot) {
280
42
      if (slot->kind == XS_NUMBER_KIND) {
281
21
      fpclass = c_fpclassify(slot->value.number);
282
21
      if (fpclass == C_FP_NAN)
283
10
        mxResult->value.boolean = 1;
284
21
    }
285
42
  }
286
43
}
287
288
void fx_Number_isSafeInteger(txMachine* the)
289
4.10k
{
290
4.10k
  int fpclass;
291
4.10k
  txSlot* slot = (mxArgc < 1) ?  C_NULL : mxArgv(0);
292
4.10k
  mxResult->kind = XS_BOOLEAN_KIND;
293
4.10k
    mxResult->value.boolean = 0;
294
4.10k
    if (slot) {
295
4.10k
      if (slot->kind == XS_INTEGER_KIND)
296
7
      mxResult->value.boolean = 1;
297
4.09k
      else if (slot->kind == XS_NUMBER_KIND) {
298
26
      fpclass = c_fpclassify(slot->value.number);
299
26
      if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) {
300
22
        txNumber check = c_trunc(slot->value.number);
301
22
        if (slot->value.number == check) {
302
12
          if ((C_MIN_SAFE_INTEGER <= check) && (check <= C_MAX_SAFE_INTEGER))
303
7
            mxResult->value.boolean = 1;
304
12
        }
305
22
      }
306
26
    }
307
4.10k
  }
308
4.10k
}
309
310
void fx_Number_prototype_toExponential(txMachine* the)
311
70.6k
{
312
70.6k
  char buffer[256];
313
70.6k
  txInteger mode = 0;
314
70.6k
  txNumber precision = 0;
315
70.6k
  txNumber value;
316
70.6k
  txSlot* slot = fxCheckNumber(the, mxThis);
317
70.6k
  if (!slot) mxTypeError("this: not a number");
318
70.6k
  value = slot->value.number;
319
70.6k
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
320
70.5k
    precision = fxToNumber(the, mxArgv(0));
321
70.5k
    if (c_isnan(precision))
322
4
      precision = 0;
323
70.5k
    else if (c_isfinite(precision))
324
70.5k
      precision = c_trunc(precision);
325
70.5k
  }
326
22
  else
327
22
    precision = 0;
328
70.6k
  if (c_isnan(value))
329
8
    precision = 0;
330
70.5k
  else if (c_isfinite(value)) {
331
149
    if ((precision < 0) || (100 < precision))
332
7
      mxRangeError("invalid fractionDigits");
333
142
    if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0)))
334
120
      precision++;
335
142
    mode = 'e';
336
142
  }
337
70.4k
  else
338
70.4k
    precision = 0;
339
70.5k
  fxNumberToString(the, slot->value.number, buffer, sizeof(buffer), mode, (int)precision);
340
70.5k
  fxCopyStringC(the, mxResult, buffer);
341
70.5k
}
342
343
void fx_Number_prototype_toFixed(txMachine* the)
344
113k
{
345
113k
  char buffer[256];
346
113k
  txInteger mode = 0;
347
113k
  txNumber precision = 0;
348
113k
  txNumber value;
349
113k
  txSlot* slot = fxCheckNumber(the, mxThis);
350
113k
  if (!slot) mxTypeError("this: not a number");
351
113k
  value = slot->value.number;
352
113k
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
353
106k
    precision = fxToNumber(the, mxArgv(0));
354
106k
    if (c_isnan(precision))
355
900
      precision = 0;
356
105k
    else if (c_isfinite(precision))
357
105k
      precision = c_trunc(precision);
358
106k
  }
359
7.14k
  else
360
7.14k
    precision = 0;
361
113k
  if ((precision < 0) || (100 < precision))
362
6
    mxRangeError("invalid fractionDigits");
363
113k
  if (c_fabs(value) >= 1e21)
364
181
    precision = 0;
365
113k
  else
366
113k
    mode = 'f';
367
113k
  fxNumberToString(the, value, buffer, sizeof(buffer), mode, (int)precision);
368
113k
  fxCopyStringC(the, mxResult, buffer);
369
113k
}
370
371
void fx_Number_prototype_toLocaleString(txMachine* the)
372
13
{
373
13
  txSlot* slot = fxCheckNumber(the, mxThis);
374
13
  if (!slot) mxTypeError("this: not a number");
375
13
  mxResult->kind = slot->kind;
376
13
  mxResult->value = slot->value;
377
13
  fxToString(the, mxResult);
378
13
}
379
380
void fx_Number_prototype_toPrecision(txMachine* the)
381
610k
{
382
610k
  char buffer[256];
383
610k
  txInteger mode = 0;
384
610k
  txNumber precision = 0;
385
610k
  txNumber value;
386
610k
  txSlot* slot = fxCheckNumber(the, mxThis);
387
610k
  if (!slot) mxTypeError("this: not a number");
388
610k
  value = slot->value.number;
389
610k
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0))) {
390
569k
    precision = fxToNumber(the, mxArgv(0));
391
569k
    if (c_isnan(precision))
392
4
      precision = 0;
393
569k
    else if (c_isfinite(precision))
394
569k
      precision = c_trunc(precision);
395
569k
    if (c_isnan(value))
396
139k
      precision = 0;
397
430k
    else if (c_isfinite(value)) {
398
396k
      if ((precision < 1) || (100 < precision))
399
8
        mxRangeError("invalid precision");
400
396k
      mode = 'g';
401
396k
    }
402
33.7k
    else
403
33.7k
      precision = 0;
404
569k
  }
405
610k
  fxNumberToString(the, value, buffer, sizeof(buffer), mode, (int)precision);
406
610k
  fxCopyStringC(the, mxResult, buffer);
407
610k
}
408
409
void fx_Number_prototype_toString(txMachine* the)
410
831k
{
411
831k
  txInteger radix;
412
831k
  txSlot* slot = fxCheckNumber(the, mxThis);
413
831k
  if (!slot) mxTypeError("this: not a number");
414
831k
  if ((mxArgc > 0) && (!mxIsUndefined(mxArgv(0)))) {
415
831k
    radix = fxToInteger(the, mxArgv(0));
416
831k
    if ((radix < 2) || (36 < radix))
417
1.07k
      mxRangeError("invalid radix");
418
831k
  }
419
286
  else  
420
286
    radix = 10;
421
830k
  mxResult->kind = slot->kind;
422
830k
  mxResult->value = slot->value;
423
830k
  if (radix == 10)
424
286
    fxToString(the, mxResult);
425
830k
  else {
426
830k
    txNumber value = mxResult->value.number;
427
830k
    switch (c_fpclassify(value)) {
428
400k
    case C_FP_INFINITE:
429
400k
      if (value < 0)
430
260k
        fxStringX(the, mxResult, "-Infinity");
431
140k
      else
432
140k
        fxStringX(the, mxResult, "Infinity");
433
400k
      break;
434
136
    case C_FP_NAN:
435
136
      fxStringX(the, mxResult, "NaN");
436
136
      break;
437
273k
    case C_FP_ZERO:
438
273k
      fxStringX(the, mxResult, "0");
439
273k
      break;
440
155k
    default: {
441
      // Thanks Google V8 for the fraction part
442
155k
      static const char gxDigits[] ICACHE_FLASH_ATTR = "0123456789abcdefghijklmnopqrstuvwxyz";
443
155k
      txInteger minus;
444
155k
      txNumber integer;
445
155k
      txNumber fraction;
446
155k
      txNumber next;
447
155k
      txU8* nextCast = (txU8*)&next;
448
155k
      txNumber delta;
449
155k
      txSize length;
450
155k
      txString string;
451
155k
      txNumber modulo;
452
155k
      if (value < 0) {
453
3.64k
        minus = 1;
454
3.64k
        value = -value;
455
3.64k
      } 
456
151k
      else
457
151k
        minus = 0;
458
155k
      integer = c_floor(value);
459
155k
      fraction = value - integer;
460
155k
      next = value;
461
155k
      *nextCast = *nextCast + 1;
462
155k
      delta = 0.5 * (next - value);
463
155k
      next = 0;
464
155k
      *nextCast = *nextCast + 1;
465
155k
      if (delta < next)
466
0
        delta = next;
467
155k
      length = minus + ((integer)? (txSize)c_round(c_log1p(integer) / c_log(radix)) : 0) + 1;
468
155k
      if (fraction >= delta) {
469
217k
        #define mxFractionPartLength 2048
470
6.22k
        txString dot;
471
6.22k
        txInteger i = 0;
472
6.22k
        txInteger digit;
473
6.22k
        string = mxResult->value.string = fxNewChunk(the, length + 1 + mxFractionPartLength + 1);
474
6.22k
        dot = string + length;
475
6.22k
        dot[i++] = '.';
476
217k
        do {
477
217k
          fraction *= radix;
478
217k
          delta *= radix;
479
217k
          digit = (txInteger)fraction;
480
217k
          dot[i++] = c_read8(gxDigits + digit);
481
217k
          fraction -= digit;
482
217k
          if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
483
80.7k
            if (fraction + delta > 1) {
484
3.03k
              for (;;) {
485
3.03k
                char c;
486
3.03k
                i--;
487
3.03k
                if (i == 0) {
488
0
                  integer += 1;
489
0
                  break;
490
0
                }
491
3.03k
                c = dot[i];
492
3.03k
                digit = c > '9' ? (c - 'a' + 10) : (c - '0');
493
3.03k
                if (digit + 1 < radix) {
494
3.00k
                  dot[i++] = c_read8(gxDigits + digit + 1);
495
3.00k
                  break;
496
3.00k
                }
497
3.03k
              }
498
3.00k
              break;
499
3.00k
            }
500
80.7k
          }
501
217k
        } while ((fraction >= delta) && (i < mxFractionPartLength));
502
6.22k
        dot[i++] = 0;
503
6.22k
        length += i;
504
6.22k
        string = dot;
505
6.22k
      }
506
149k
      else {
507
149k
        length += 1;
508
149k
        string = mxResult->value.string = fxNewChunk(the, length);
509
149k
        string += length;
510
149k
        *(--string) = 0;
511
149k
      }
512
155k
      modulo = C_MAX_SAFE_INTEGER * radix;
513
51.0M
      while (integer > modulo) {
514
50.9M
        *(--string) = '0';
515
50.9M
        integer = integer / radix;
516
50.9M
      }
517
5.21M
      do {
518
5.21M
        modulo = c_fmod(integer, radix);
519
5.21M
        *(--string) = c_read8(gxDigits + (txInteger)modulo);
520
5.21M
        integer = (integer - modulo) / radix;
521
5.21M
      } while (integer >= 1);
522
155k
      if (minus) {
523
3.64k
        *(--string) = '-';
524
3.64k
      }
525
155k
      minus = (txInteger)(string - mxResult->value.string);
526
155k
      if (minus > 0) {
527
3.40k
        length -= minus;
528
3.40k
        c_memmove(mxResult->value.string, string, length);
529
3.40k
      }
530
155k
      mxResult->value.string = fxRenewChunk(the, mxResult->value.string, length);
531
155k
      mxResult->kind = XS_STRING_KIND;
532
155k
    }}
533
830k
  }
534
830k
}
535
536
void fx_Number_prototype_valueOf(txMachine* the)
537
163k
{
538
163k
  txSlot* slot = fxCheckNumber(the, mxThis);
539
163k
  if (!slot) mxTypeError("this: not a number");
540
163k
  mxResult->kind = slot->kind;
541
163k
  mxResult->value = slot->value;
542
163k
}
543
544
txSlot* fxCheckNumber(txMachine* the, txSlot* it)
545
1.78M
{
546
1.78M
  txSlot* result = C_NULL;
547
1.78M
  if (it->kind == XS_INTEGER_KIND) {
548
253k
    fxToNumber(the, it);
549
253k
    result = it;
550
253k
  }
551
1.53M
  else if (it->kind == XS_NUMBER_KIND)
552
1.37M
    result = it;
553
161k
  else if (it->kind == XS_REFERENCE_KIND) {
554
161k
    txSlot* instance = it->value.reference;
555
161k
    it = instance->next;
556
161k
    if ((it) && (it->flag & XS_INTERNAL_FLAG) && (it->kind == XS_NUMBER_KIND))
557
161k
      result = it;
558
161k
  }
559
1.78M
  return result;
560
1.78M
}