@@ -11,6 +11,18 @@ namespace Js
11
11
return RecyclerNew (scriptContext->GetRecycler (), JavascriptBigInt, content, cchUseLength, isNegative, scriptContext->GetLibrary ()->GetBigIntTypeStatic ());
12
12
}
13
13
14
+ JavascriptBigInt * JavascriptBigInt::CreateZero (ScriptContext * scriptContext)
15
+ {
16
+ JavascriptBigInt * bigintNew = RecyclerNew (scriptContext->GetRecycler (), JavascriptBigInt, scriptContext->GetLibrary ()->GetBigIntTypeStatic ());
17
+ bigintNew->m_length = 1 ;
18
+ bigintNew->m_isNegative = false ;
19
+ bigintNew->m_maxLength = 1 ;
20
+ bigintNew->m_digits = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), digit_t , bigintNew->m_length );
21
+ bigintNew->m_digits [0 ] = 0 ;
22
+
23
+ return bigintNew;
24
+ }
25
+
14
26
JavascriptBigInt * JavascriptBigInt::New (JavascriptBigInt * pbi, ScriptContext * scriptContext)
15
27
{
16
28
JavascriptBigInt * bigintNew = RecyclerNew (scriptContext->GetRecycler (), JavascriptBigInt, scriptContext->GetLibrary ()->GetBigIntTypeStatic ());
@@ -88,25 +100,25 @@ namespace Js
88
100
return true ;
89
101
}
90
102
91
- bool JavascriptBigInt::Resize (digit_t length)
103
+ void JavascriptBigInt::Resize (digit_t length)
92
104
{
93
105
digit_t *digits;
94
106
95
107
if (length <= m_maxLength)
96
108
{
97
- return true ;
109
+ return ;
98
110
}
99
111
100
112
length += length;// double size
101
113
if (SIZE_MAX / sizeof (digit_t ) < length) // overflow
102
114
{
103
- return false ;
115
+ JavascriptError::ThrowRangeError ( this -> GetScriptContext (), VBSERR_TypeMismatch, _u ( " Resize BigInt " )) ;
104
116
}
105
117
106
118
digits = RecyclerNewArrayLeaf (this ->GetScriptContext ()->GetRecycler (), digit_t , length);
107
119
if (NULL == digits)
108
120
{
109
- return false ;
121
+ JavascriptError::ThrowRangeError ( this -> GetScriptContext (), VBSERR_TypeMismatch, _u ( " Resize BigInt " )) ;
110
122
}
111
123
112
124
if (0 < m_length) // in this case, we need to copy old data over
@@ -116,8 +128,6 @@ namespace Js
116
128
117
129
m_digits = digits;
118
130
m_maxLength = length;
119
-
120
- return true ;
121
131
}
122
132
123
133
template <typename EncodedChar>
@@ -200,9 +210,9 @@ namespace Js
200
210
}
201
211
if (carry > 0 ) // increase length
202
212
{
203
- if (result->m_length >= result->m_maxLength && !result-> Resize (result-> m_length + 1 ) )
213
+ if (result->m_length >= result->m_maxLength )
204
214
{
205
- AssertOrFailFastMsg ( false , " AbsoluteIncrement overflow " );
215
+ result-> Resize (result-> m_length + 1 );
206
216
}
207
217
result->m_digits [result->m_length ++] = carry;
208
218
}
@@ -328,9 +338,9 @@ namespace Js
328
338
}
329
339
if (0 < digitAdd) // length increase by 1
330
340
{
331
- if (m_length >= m_maxLength && ! Resize (m_length + 1 ) )
341
+ if (m_length >= m_maxLength)
332
342
{
333
- return false ;
343
+ Resize (m_length + 1 ) ;
334
344
}
335
345
m_digits[m_length++] = digitAdd;
336
346
}
@@ -351,16 +361,21 @@ namespace Js
351
361
}
352
362
}
353
363
354
- digit_t index;
355
364
int sign = m_isNegative ? -1 : 1 ;
365
+ return sign * JavascriptBigInt::CompareAbsolute (pbi);
366
+ }
367
+
368
+ int JavascriptBigInt::CompareAbsolute (JavascriptBigInt *pbi)
369
+ {
370
+ digit_t index;
356
371
357
372
if (m_length > pbi->m_length )
358
373
{
359
- return 1 * sign ;
374
+ return 1 ;
360
375
}
361
376
if (m_length < pbi->m_length )
362
377
{
363
- return -1 * sign ;
378
+ return -1 ;
364
379
}
365
380
if (0 == m_length)
366
381
{
@@ -375,7 +390,7 @@ namespace Js
375
390
}
376
391
Assert (m_digits[index] != pbi->m_digits [index]);
377
392
378
- return sign*(( m_digits[index] > pbi->m_digits [index]) ? 1 : -1 ) ;
393
+ return ( m_digits[index] > pbi->m_digits [index]) ? 1 : -1 ;
379
394
}
380
395
381
396
bool JavascriptBigInt::LessThan (Var aLeft, Var aRight)
@@ -397,4 +412,167 @@ namespace Js
397
412
return (leftBigInt->Compare (rightBigInt) == 0 );
398
413
}
399
414
415
+ // pbi1 += pbi2 assume pbi1 has length no less than pbi2
416
+ void JavascriptBigInt::AddAbsolute (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
417
+ {
418
+ Assert (pbi1->m_length >= pbi2->m_length );
419
+ digit_t carryDigit = 0 ;
420
+ digit_t *pDigit1 = pbi1->m_digits ;
421
+ digit_t *pDigit2 = pbi2->m_digits ;
422
+ digit_t i = 0 ;
423
+
424
+ for (; i < pbi2->m_length ; i++)
425
+ {
426
+ digit_t tempCarryDigit = 0 ;
427
+ pDigit1[i] = JavascriptBigInt::AddDigit (pDigit1[i], pDigit2[i], &tempCarryDigit);
428
+ pDigit1[i] = JavascriptBigInt::AddDigit (pDigit1[i], carryDigit, &tempCarryDigit);
429
+ carryDigit = tempCarryDigit;
430
+ }
431
+
432
+ for (; i < pbi1->m_length && carryDigit > 0 ; i++)
433
+ {
434
+ digit_t tempCarryDigit = 0 ;
435
+ pDigit1[i] = JavascriptBigInt::AddDigit (pDigit1[i], carryDigit, &tempCarryDigit);
436
+ carryDigit = tempCarryDigit;
437
+ }
438
+
439
+ if (0 < carryDigit) // length increase by 1
440
+ {
441
+ if (pbi1->m_length >= pbi1->m_maxLength )
442
+ {
443
+ pbi1->Resize (pbi1->m_length + 1 );
444
+ }
445
+ pbi1->m_digits [pbi1->m_length ++] = carryDigit;
446
+ }
447
+ }
448
+
449
+ // pbi1 -= pbi2 assume |pbi1| > |pbi2|
450
+ void JavascriptBigInt::SubAbsolute (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
451
+ {
452
+ Assert (pbi1->CompareAbsolute (pbi2) == 1 );
453
+ digit_t carryDigit = 0 ;
454
+ digit_t *pDigit1 = pbi1->m_digits ;
455
+ digit_t *pDigit2 = pbi2->m_digits ;
456
+ digit_t i = 0 ;
457
+
458
+ for (; i < pbi2->m_length ; i++)
459
+ {
460
+ digit_t tempCarryDigit = 0 ;
461
+ pDigit1[i] = JavascriptBigInt::SubDigit (pDigit1[i], pDigit2[i], &tempCarryDigit);
462
+ pDigit1[i] = JavascriptBigInt::SubDigit (pDigit1[i], carryDigit, &tempCarryDigit);
463
+ carryDigit = tempCarryDigit;
464
+ }
465
+
466
+ for (; i < pbi1->m_length && carryDigit > 0 ; i++)
467
+ {
468
+ digit_t tempCarryDigit = 0 ;
469
+ pDigit1[i] = JavascriptBigInt::SubDigit (pDigit1[i], carryDigit, &tempCarryDigit);
470
+ carryDigit = tempCarryDigit;
471
+ }
472
+ // adjust length
473
+ while ((pbi1->m_length >0 ) && (pbi1->m_digits [pbi1->m_length -1 ] == 0 ))
474
+ {
475
+ pbi1->m_length --;
476
+ }
477
+ Assert (pbi1->m_length > 0 );
478
+ }
479
+
480
+ JavascriptBigInt * JavascriptBigInt::Sub (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
481
+ {
482
+ if (JavascriptBigInt::IsZero (pbi1))
483
+ {
484
+ pbi2->m_isNegative = !pbi2->m_isNegative ;
485
+ return pbi2;
486
+ }
487
+ if (JavascriptBigInt::IsZero (pbi2))
488
+ {
489
+ return pbi1;
490
+ }
491
+
492
+ if (pbi2->m_isNegative )
493
+ {
494
+ pbi2->m_isNegative = false ;
495
+ return JavascriptBigInt::Add (pbi1, pbi2);// a-(-b)=a+b
496
+ }
497
+
498
+ if (pbi1->m_isNegative ) // -a-b=-(a+b)
499
+ {
500
+ if (pbi1->m_length >= pbi2->m_length )
501
+ {
502
+ JavascriptBigInt::AddAbsolute (pbi1, pbi2);
503
+ return pbi1;
504
+ }
505
+ JavascriptBigInt::AddAbsolute (pbi2, pbi1);
506
+ return pbi2;
507
+ }
508
+ else // both positive
509
+ {
510
+ switch (pbi1->CompareAbsolute (pbi2))
511
+ {
512
+ case 0 : // a -a = 0
513
+ return JavascriptBigInt::CreateZero (pbi1->GetScriptContext ());
514
+ case 1 :
515
+ JavascriptBigInt::SubAbsolute (pbi1, pbi2); // a - b > 0
516
+ return pbi1;
517
+ default :
518
+ pbi2->m_isNegative = true ;
519
+ JavascriptBigInt::SubAbsolute (pbi2, pbi1); // a - b = - (b-a) < 0
520
+ return pbi2;
521
+ }
522
+ }
523
+ }
524
+
525
+ JavascriptBigInt * JavascriptBigInt::Add (JavascriptBigInt * pbi1, JavascriptBigInt * pbi2)
526
+ {
527
+ if (JavascriptBigInt::IsZero (pbi1))
528
+ {
529
+ return pbi2;
530
+ }
531
+ if (JavascriptBigInt::IsZero (pbi2))
532
+ {
533
+ return pbi1;
534
+ }
535
+
536
+ if (pbi1->m_isNegative == pbi2->m_isNegative ) // (-a)+(-b) = -(a+b)
537
+ {
538
+ if (pbi1->m_length >= pbi2->m_length )
539
+ {
540
+ JavascriptBigInt::AddAbsolute (pbi1, pbi2);
541
+ return pbi1;
542
+ }
543
+ JavascriptBigInt::AddAbsolute (pbi2, pbi1);
544
+ return pbi2;
545
+ }
546
+ else
547
+ {
548
+ switch (pbi1->CompareAbsolute (pbi2))
549
+ {
550
+ case 0 :
551
+ return JavascriptBigInt::CreateZero (pbi1->GetScriptContext ()); // a + (-a) = -a + a = 0
552
+ case 1 :
553
+ JavascriptBigInt::SubAbsolute (pbi1, pbi2); // a + (-b) = a - b or (-a) + b = -(a-b)
554
+ return pbi1;
555
+ default :
556
+ JavascriptBigInt::SubAbsolute (pbi2, pbi1); // -a + b = b - a or a + (-b) = -(b-a)
557
+ return pbi2;
558
+ }
559
+ }
560
+ }
561
+
562
+ Var JavascriptBigInt::Add (Var aLeft, Var aRight)
563
+ {
564
+ JavascriptBigInt *leftBigInt = VarTo<JavascriptBigInt>(aLeft);
565
+ JavascriptBigInt *rightBigInt = VarTo<JavascriptBigInt>(aRight);
566
+ return JavascriptBigInt::Add (JavascriptBigInt::New (leftBigInt, leftBigInt->GetScriptContext ()), JavascriptBigInt::New (rightBigInt, rightBigInt->GetScriptContext ()));
567
+ // TODO: Consider deferring creation of new instances until we need them
568
+ }
569
+
570
+ Var JavascriptBigInt::Sub (Var aLeft, Var aRight)
571
+ {
572
+ JavascriptBigInt *leftBigInt = VarTo<JavascriptBigInt>(aLeft);
573
+ JavascriptBigInt *rightBigInt = VarTo<JavascriptBigInt>(aRight);
574
+ return JavascriptBigInt::Sub (JavascriptBigInt::New (leftBigInt, leftBigInt->GetScriptContext ()), JavascriptBigInt::New (rightBigInt, rightBigInt->GetScriptContext ()));
575
+ // TODO: Consider deferring creation of new instances until we need them
576
+ }
577
+
400
578
} // namespace Js
0 commit comments