2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 2012-2013, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 Original author: Zhi Feng Huang
30 #include <CoreFoundation/CFBigNumber.h>
35 #include "CFInternal.h"
43 #define kCFNumberSInt128Type 17
45 CF_EXPORT CFNumberType
_CFNumberGetType2(CFNumberRef number
);
51 typedef __int128_t int128_t
;
56 typedef __uint128_t uint128_t
;
60 #define INT128_MIN ((__int128_t)0 - ((__int128_t)1 << 126) - ((__int128_t)1 << 126))
64 #define INT128_MAX ((__int128_t)-1 + ((__int128_t)1 << 126) + ((__int128_t)1 << 126))
68 #define UINT128_MAX (((__uint128_t)1 << 127) - (__uint128_t)1 + ((__uint128_t)1 << 127))
74 #define BIG_DIGITS_LIMIT 1000000000L
75 #define BIG_DIGITS_LIMIT_2 ((uint64_t)BIG_DIGITS_LIMIT * (uint64_t)BIG_DIGITS_LIMIT)
76 #define BIG_DIGITS_LIMIT_3 ((__uint128_t)BIG_DIGITS_LIMIT_2 * (__uint128_t)BIG_DIGITS_LIMIT)
77 #define BIG_DIGITS_LIMIT_4 ((__uint128_t)BIG_DIGITS_LIMIT_3 * (__uint128_t)BIG_DIGITS_LIMIT)
79 #define GET_FIFTH_DIGIT(A) (A / BIG_DIGITS_LIMIT_4)
80 #define GET_FOURTH_DIGIT(A) (A / BIG_DIGITS_LIMIT_3)
81 #define GET_THIRD_DIGIT(A) (A / BIG_DIGITS_LIMIT_2)
82 #define GET_SECOND_DIGIT(A) (A / BIG_DIGITS_LIMIT)
84 #define GET_REMAINDER_FIFTH_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_4)
85 #define GET_REMAINDER_FOURTH_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_3)
86 #define GET_REMAINDER_THIRD_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_2)
87 #define GET_REMAINDER_SECOND_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT)
90 void _CFBigNumInitWithInt8(_CFBigNum
*r
, int8_t inNum
) {
91 memset(r
, 0, sizeof(*r
));
92 uint8_t unsignInNum
= inNum
;
95 unsignInNum
= -1 * inNum
;
97 r
->digits
[0] = unsignInNum
;
100 void _CFBigNumInitWithInt16(_CFBigNum
*r
, int16_t inNum
) {
101 memset(r
, 0, sizeof(*r
));
102 uint16_t unsignInNum
= inNum
;
105 unsignInNum
= -1 * inNum
;
107 r
->digits
[0] = unsignInNum
;
110 void _CFBigNumInitWithInt32(_CFBigNum
*r
, int32_t inNum
) {
111 memset(r
, 0, sizeof(*r
));
112 uint32_t unsignInNum
= inNum
;
115 unsignInNum
= -1 * inNum
;
117 uint32_t dig0
= GET_SECOND_DIGIT(unsignInNum
);
118 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, dig0
);
122 void _CFBigNumInitWithInt64(_CFBigNum
*r
, int64_t inNum
) {
123 memset(r
, 0, sizeof(*r
));
124 uint64_t unsignInNum
= inNum
;
127 unsignInNum
= -1 * inNum
;
129 uint32_t dig2
= GET_THIRD_DIGIT(unsignInNum
);
130 unsignInNum
= GET_REMAINDER_THIRD_DIGIT(unsignInNum
, (uint64_t)dig2
);
131 uint32_t dig1
= GET_SECOND_DIGIT(unsignInNum
);
132 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, (uint64_t)dig1
);
138 void _CFBigNumInitWithInt128(_CFBigNum
*r
, __int128_t inNum
) {
139 memset(r
, 0, sizeof(*r
));
140 __uint128_t unsignInNum
= inNum
;
143 unsignInNum
= -1 * inNum
;
145 uint32_t dig4
= GET_FIFTH_DIGIT(unsignInNum
);
146 unsignInNum
= GET_REMAINDER_FIFTH_DIGIT(unsignInNum
, (__uint128_t
)dig4
);
147 uint32_t dig3
= GET_FOURTH_DIGIT(unsignInNum
);
148 unsignInNum
= GET_REMAINDER_FOURTH_DIGIT(unsignInNum
, (__uint128_t
)dig3
);
149 uint32_t dig2
= GET_THIRD_DIGIT(unsignInNum
);
150 unsignInNum
= GET_REMAINDER_THIRD_DIGIT(unsignInNum
, (__uint128_t
)dig2
);
151 uint32_t dig1
= GET_SECOND_DIGIT(unsignInNum
);
152 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, (__uint128_t
)dig1
);
160 void _CFBigNumInitWithUInt8(_CFBigNum
*r
, uint8_t inNum
) {
161 memset(r
, 0, sizeof(*r
));
162 uint8_t unsignInNum
= inNum
;
163 r
->digits
[0] = unsignInNum
;
166 void _CFBigNumInitWithUInt16(_CFBigNum
*r
, uint16_t inNum
) {
167 memset(r
, 0, sizeof(*r
));
168 uint16_t unsignInNum
= inNum
;
169 r
->digits
[0] = unsignInNum
;
172 void _CFBigNumInitWithUInt32(_CFBigNum
*r
, uint32_t inNum
) {
173 memset(r
, 0, sizeof(*r
));
174 uint32_t unsignInNum
= inNum
;
175 uint32_t dig0
= GET_SECOND_DIGIT(unsignInNum
);
176 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, dig0
);
180 void _CFBigNumInitWithUInt64(_CFBigNum
*r
, uint64_t inNum
) {
181 memset(r
, 0, sizeof(*r
));
182 uint64_t unsignInNum
= inNum
;
183 uint32_t dig2
= GET_THIRD_DIGIT(unsignInNum
);
184 unsignInNum
= GET_REMAINDER_THIRD_DIGIT(unsignInNum
, (uint64_t)dig2
);
185 uint32_t dig1
= GET_SECOND_DIGIT(unsignInNum
);
186 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, (uint64_t)dig1
);
192 void _CFBigNumInitWithUInt128(_CFBigNum
*r
, __uint128_t inNum
) {
193 memset(r
, 0, sizeof(*r
));
194 __uint128_t unsignInNum
= inNum
;
195 uint32_t dig4
= GET_FIFTH_DIGIT(unsignInNum
);
196 unsignInNum
= GET_REMAINDER_FIFTH_DIGIT(unsignInNum
, (__uint128_t
)dig4
);
197 uint32_t dig3
= GET_FOURTH_DIGIT(unsignInNum
);
198 unsignInNum
= GET_REMAINDER_FOURTH_DIGIT(unsignInNum
, (__uint128_t
)dig3
);
199 uint32_t dig2
= GET_THIRD_DIGIT(unsignInNum
);
200 unsignInNum
= GET_REMAINDER_THIRD_DIGIT(unsignInNum
, (__uint128_t
)dig2
);
201 uint32_t dig1
= GET_SECOND_DIGIT(unsignInNum
);
202 r
->digits
[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum
, (__uint128_t
)dig1
);
211 int8_t _CFBigNumGetInt8(const _CFBigNum
*num
) {
212 int8_t result
= num
->digits
[0];
214 result
= -1 * result
;
219 int16_t _CFBigNumGetInt16(const _CFBigNum
*num
) {
220 int16_t result
= num
->digits
[0];
222 result
= -1 * result
;
227 int32_t _CFBigNumGetInt32(const _CFBigNum
*num
) {
228 int32_t result
= num
->digits
[0];
229 result
+= num
->digits
[1] * BIG_DIGITS_LIMIT
;
231 result
= -1 * result
;
236 int64_t _CFBigNumGetInt64(const _CFBigNum
*num
) {
237 int64_t result
= num
->digits
[0];
238 result
+= (int64_t)num
->digits
[1] * BIG_DIGITS_LIMIT
;
239 result
+= (int64_t)num
->digits
[2] * BIG_DIGITS_LIMIT_2
;
241 result
= -1 * result
;
247 __int128_t
_CFBigNumGetInt128(const _CFBigNum
*num
) {
248 __int128_t result
= num
->digits
[0];
249 result
+= (__int128_t
)num
->digits
[1] * BIG_DIGITS_LIMIT
;
250 result
+= (__int128_t
)num
->digits
[2] * BIG_DIGITS_LIMIT_2
;
251 result
+= (__int128_t
)num
->digits
[3] * BIG_DIGITS_LIMIT_3
;
252 result
+= (__int128_t
)num
->digits
[4] * BIG_DIGITS_LIMIT_4
;
254 result
= -1 * result
;
260 uint8_t _CFBigNumGetUInt8(const _CFBigNum
*num
) {
261 uint8_t result
= num
->digits
[0];
265 uint16_t _CFBigNumGetUInt16(const _CFBigNum
*num
) {
266 uint16_t result
= num
->digits
[0];
270 uint32_t _CFBigNumGetUInt32(const _CFBigNum
*num
) {
271 uint32_t result
= num
->digits
[0];
272 result
+= num
->digits
[1] * BIG_DIGITS_LIMIT
;
276 uint64_t _CFBigNumGetUInt64(const _CFBigNum
*num
) {
277 uint64_t result
= num
->digits
[0];
278 result
+= (uint64_t)num
->digits
[1] * BIG_DIGITS_LIMIT
;
279 result
+= (uint64_t)num
->digits
[2] * BIG_DIGITS_LIMIT_2
;
284 __uint128_t
_CFBigNumGetUInt128(const _CFBigNum
*num
) {
285 __uint128_t result
= num
->digits
[0];
286 result
+= (__uint128_t
)num
->digits
[1] * BIG_DIGITS_LIMIT
;
287 result
+= (__uint128_t
)num
->digits
[2] * BIG_DIGITS_LIMIT_2
;
288 result
+= (__uint128_t
)num
->digits
[3] * BIG_DIGITS_LIMIT_3
;
289 result
+= (__uint128_t
)num
->digits
[4] * BIG_DIGITS_LIMIT_4
;
295 void _CFBigNumInitWithCFNumber(_CFBigNum
*r
, CFNumberRef inNum
) {
296 uint8_t bytes
[128 + 16];
297 memset(bytes
, 0, sizeof(bytes
));
298 // round bytes up to next multiple of 16; compiler attributes won't always guarantee big alignment
299 void *bytesa
= (uint8_t *)(((uintptr_t)bytes
/ 16) * 16 + 16);
300 CFNumberType type
= _CFNumberGetType2(inNum
);
301 CFNumberGetValue(inNum
, type
, bytesa
);
302 _CFBigNumInitWithBytes(r
, bytesa
, type
);
305 void _CFBigNumInitWithBytes(_CFBigNum
*r
, const void *bytes
, CFNumberType type
) {
307 case kCFNumberSInt8Type
:
308 _CFBigNumInitWithInt8(r
, *(int8_t *)bytes
);
310 case kCFNumberSInt16Type
:
311 _CFBigNumInitWithInt16(r
, *(int16_t *)bytes
);
313 case kCFNumberSInt32Type
:
314 _CFBigNumInitWithInt32(r
, *(int32_t *)bytes
);
316 case kCFNumberSInt64Type
:
317 _CFBigNumInitWithInt64(r
, *(int64_t *)bytes
);
319 case kCFNumberCharType
:
320 _CFBigNumInitWithInt8(r
, *(int8_t *)bytes
);
322 case kCFNumberShortType
:
323 _CFBigNumInitWithInt16(r
, *(int16_t *)bytes
);
325 case kCFNumberIntType
:
326 _CFBigNumInitWithInt32(r
, *(int32_t *)bytes
);
328 case kCFNumberLongType
:
329 if (sizeof(long) == 8) {
330 _CFBigNumInitWithInt64(r
, *(int64_t *)bytes
);
332 _CFBigNumInitWithInt32(r
, *(int32_t *)bytes
);
335 case kCFNumberLongLongType
:
336 _CFBigNumInitWithInt64(r
, *(int64_t *)bytes
);
338 case kCFNumberCFIndexType
:
339 if (sizeof(CFIndex
) == 8) {
340 _CFBigNumInitWithInt64(r
, *(int64_t *)bytes
);
342 _CFBigNumInitWithInt32(r
, *(int32_t *)bytes
);
345 case kCFNumberNSIntegerType
:
346 if (sizeof(long) == 8) { // NSInteger follows long
347 _CFBigNumInitWithInt64(r
, *(int64_t *)bytes
);
349 _CFBigNumInitWithInt32(r
, *(int32_t *)bytes
);
353 case kCFNumberSInt128Type
: {
355 memmove(&s
, bytes
, sizeof(CFSInt128Struct
)); // the hard way because bytes might not be aligned
356 __int128_t val
= (__int128_t
)s
.low
+ ((__int128_t
)s
.high
<< 64);
357 _CFBigNumInitWithInt128(r
, val
);
366 CFNumberRef
_CFNumberCreateWithBigNum(const _CFBigNum
*input
) {
367 if (0 == input
->digits
[4] && 0 == input
->digits
[3] && 0 == input
->digits
[2] && 0 == input
->digits
[1]) {
368 // This bumps up the size of the most negative n-bit value to the next larger size; oh well
369 if (input
->digits
[0] <= INT8_MAX
) {
370 int8_t num
= _CFBigNumGetInt8(input
);
371 CFNumberRef result
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt8Type
, (const void *)&num
);
373 } else if (input
->digits
[0] <= INT16_MAX
) {
374 int16_t num
= _CFBigNumGetInt16(input
);
375 CFNumberRef result
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt16Type
, (const void *)&num
);
379 _CFBigNum maxlimit
, minlimit
;
380 if (0 == input
->digits
[4] && 0 == input
->digits
[3] && 0 == input
->digits
[2]) {
381 _CFBigNumInitWithInt32(&maxlimit
, INT32_MAX
);
382 _CFBigNumInitWithInt32(&minlimit
, INT32_MIN
);
383 CFComparisonResult cr
= _CFBigNumCompare(input
, &maxlimit
);
384 CFComparisonResult crn
= _CFBigNumCompare(input
, &minlimit
);
385 if ((kCFCompareLessThan
== cr
|| kCFCompareEqualTo
== cr
) && (kCFCompareLessThan
!= crn
)) {
386 int32_t num
= _CFBigNumGetInt32(input
);
387 CFNumberRef result
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, (const void *)&num
);
391 if (0 == input
->digits
[4] && 0 == input
->digits
[3]) {
392 _CFBigNumInitWithInt64(&maxlimit
, INT64_MAX
);
393 _CFBigNumInitWithInt64(&minlimit
, INT64_MIN
);
394 CFComparisonResult cr
= _CFBigNumCompare(input
, &maxlimit
);
395 CFComparisonResult crn
= _CFBigNumCompare(input
, &minlimit
);
396 if ((kCFCompareLessThan
== cr
|| kCFCompareEqualTo
== cr
) && (kCFCompareLessThan
!= crn
)) {
397 int64_t num
= _CFBigNumGetInt64(input
);
398 CFNumberRef result
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt64Type
, (const void *)&num
);
403 _CFBigNumInitWithInt128(&maxlimit
, INT128_MAX
);
404 _CFBigNumInitWithInt128(&minlimit
, INT128_MIN
);
405 CFComparisonResult cr
= _CFBigNumCompare(input
, &maxlimit
);
406 CFComparisonResult crn
= _CFBigNumCompare(input
, &minlimit
);
407 if ((kCFCompareLessThan
== cr
|| kCFCompareEqualTo
== cr
) && (kCFCompareLessThan
!= crn
)) {
408 __int128_t num
= _CFBigNumGetInt128(input
);
409 CFNumberRef result
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt128Type
, (const void *)&num
);
416 CFComparisonResult
_CFBigNumCompare(const _CFBigNum
*a
, const _CFBigNum
*b
) {
417 Boolean sameSign
= a
->sign
== b
->sign
;
419 Boolean negative
= a
->sign
< 0;
420 for (CFIndex i
= sizeof(a
->digits
) / sizeof(a
->digits
[0]); i
--;) {
421 if (a
->digits
[i
] < b
->digits
[i
]) {
422 return !negative
? kCFCompareLessThan
: kCFCompareGreaterThan
;
424 if (a
->digits
[i
] > b
->digits
[i
]) {
425 return negative
? kCFCompareLessThan
: kCFCompareGreaterThan
;
428 return kCFCompareEqualTo
;
430 return (a
->sign
< b
->sign
) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
434 // do not care about the sign
435 static Boolean
_CFBigNumAbsoluteLessThan(const _CFBigNum
*a
, const _CFBigNum
*b
) {
436 for (CFIndex i
= sizeof(a
->digits
) / sizeof(a
->digits
[0]); i
--;) {
437 if (a
->digits
[i
] < b
->digits
[i
]) {
440 if (a
->digits
[i
] > b
->digits
[i
]) {
448 void _CFBigNumNeg(_CFBigNum
*r
, const _CFBigNum
*a
) {
449 memmove(r
, a
, sizeof(*a
));
450 Boolean aIsZero
= true;
451 for (CFIndex i
= 0; i
< sizeof(a
->digits
) / sizeof(a
->digits
[0]); i
++) {
452 if (a
->digits
[i
] != 0) {
457 // if a is zero, we do not flip the sign
461 r
->sign
= r
->sign
* r
->sign
- 1;
465 uint8_t _CFBigNumAdd(_CFBigNum
*r
, const _CFBigNum
*a
, const _CFBigNum
*b
) {
467 Boolean sameSign
= a
->sign
== b
->sign
;
469 for (CFIndex i
= 0; i
< sizeof(a
->digits
) / sizeof(a
->digits
[0]); i
++) {
470 uint32_t result
= a
->digits
[i
] + b
->digits
[i
] + carry
;
471 if (result
> BIG_DIGITS_LIMIT
) {
473 result
-= BIG_DIGITS_LIMIT
;
477 r
->digits
[i
] = result
;
482 // the algorithm here is to find the larger one and do the subtraction and then neg the result if necessary
483 const _CFBigNum
*bigNum
= NULL
;
484 const _CFBigNum
*smallNum
= NULL
;
485 if (_CFBigNumAbsoluteLessThan(a
, b
)) {
492 for (int i
= 0; i
< sizeof(a
->digits
) / sizeof(a
->digits
[0]); i
++) {
493 int64_t result
= (int64_t)bigNum
->digits
[i
] - (int64_t)smallNum
->digits
[i
] - carry
;
496 result
+= BIG_DIGITS_LIMIT
;
500 r
->digits
[i
] = result
;
502 if (bigNum
->sign
< 0) {
511 uint8_t _CFBigNumSub(_CFBigNum
*r
, const _CFBigNum
*a
, const _CFBigNum
*b
) {
513 _CFBigNumNeg(&nb
, b
);
514 return _CFBigNumAdd(r
, a
, &nb
);
518 void _CFBigNumToCString(const _CFBigNum
*vp
, Boolean leading_zeros
, Boolean leading_plus
, char *buffer
, size_t buflen
) {
522 } else if (leading_plus
) {
527 snprintf(tmp
, sizeof(tmp
), "%09u%09u%09u%09u%09u", vp
->digits
[4], vp
->digits
[3], vp
->digits
[2], vp
->digits
[1], vp
->digits
[0]);
529 memset(buffer
, '0', buflen
);
530 uint32_t tocopy
= __CFMin(sizeof(tmp
), buflen
);
531 memmove(buffer
+ buflen
- tocopy
, tmp
+ sizeof(tmp
) - tocopy
, tocopy
); // copies trailing nul from tmp to nul-terminate
534 while (*s
== '0') s
++;
535 if (*s
== 0) s
--; // if tmp is all zeros, copy out at least one zero
536 strlcpy(buffer
, s
, buflen
);
540 void _CFBigNumFromCString(_CFBigNum
*r
, const char *string
) {
541 memset(r
, 0, sizeof(*r
));
542 char *copy
= (char *)calloc(strlen(string
)+1, sizeof(char));
543 memcpy(copy
, string
, strlen(string
)+1);
544 char *working
= copy
;
545 if (*working
== '-') {
548 } else if (*working
== '+') {
551 while (*working
== '0') {
555 size_t length
= strlen(working
);
556 if (length
== 0) { // the number is zero
560 while (curDigit
+ 1 < sizeof(r
->digits
) / sizeof(r
->digits
[0]) && 9 < length
) {
561 uint32_t digit
= atol(working
+length
-9);
562 r
->digits
[curDigit
] = digit
;
563 *(working
+length
-9) = 0;
567 uint32_t digit
= atol(working
);
568 r
->digits
[curDigit
] = digit
;
572 char *_CFBigNumCopyDescription(const _CFBigNum
*num
) {
573 char *result
= (char *)calloc(1024, sizeof(char));
574 sprintf(result
, "sign:%s 1st:%u 2nd:%u 3rd:%u 4th:%u 5th:%u", num
->sign
< 0 ? "-" : "+", num
->digits
[0], num
->digits
[1], num
->digits
[2], num
->digits
[3], num
->digits
[4]);