PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
int128.c
Go to the documentation of this file.
1#include <assert.h>
2#include <stdbool.h>
3#include <stdint.h>
4#include <stdlib.h>
5
6// Based upon the this lovely article by Danila Kutenin
7// https://danlark.org/2020/06/14/128-bit-division/
8
9typedef union {
11 struct
12 {
15 };
17
19{
20 int32_t clzA = a.high != 0 ? __builtin_clzll(a.high) : 64 + __builtin_clzll(a.low);
21 int32_t clzB = b.high != 0 ? __builtin_clzll(b.high) : 64 + __builtin_clzll(b.low);
22 return clzB - clzA;
23}
24
25static inline uint64_t __div128_64(uint64_t high, uint64_t low, uint64_t divisor, uint64_t* remainder)
26{
27 uint64_t result;
28 __asm__("divq %[v]" : "=a"(result), "=d"(*remainder) : [v] "r"(divisor), "a"(low), "d"(high));
29 return result;
30}
31
33{
34 uint128_split_t dividend = *(uint128_split_t*)&a;
35 uint128_split_t divisor = *(uint128_split_t*)&b;
37
38 if (divisor.raw > dividend.raw)
39 {
40 remainder = dividend;
41 if (c != NULL)
42 {
43 *c = remainder.raw;
44 }
45 return 0;
46 }
47
48 if (divisor.high == 0)
49 {
50 if (dividend.high < divisor.raw)
51 {
52 uint64_t quotient = __div128_64(dividend.high, dividend.low, divisor.low, &remainder.low);
53 if (c != NULL)
54 {
55 *c = remainder.raw;
56 }
57 return quotient;
58 }
59
60 uint128_split_t quotient;
61 quotient.high = __div128_64(0, dividend.high, divisor.low, &dividend.high);
62 quotient.low = __div128_64(dividend.high, dividend.low, divisor.low, &remainder.low);
63 if (c != NULL)
64 {
65 *c = remainder.raw;
66 }
67 return quotient.raw;
68 }
69
70 int32_t shift = __distance(dividend, divisor);
71 divisor.raw <<= shift;
72 uint128_split_t quotient = {0};
73 for (int32_t i = 0; i <= shift; i++)
74 {
75 quotient.low <<= (uint128_t)1;
76 const int128_t bit = (int128_t)(divisor.raw - dividend.raw - 1) >> (int128_t)127;
77 quotient.low |= bit & (int128_t)1;
78 dividend.raw -= divisor.raw & bit;
79 divisor.raw >>= (uint128_t)1;
80 }
81 if (c != NULL)
82 {
83 *c = dividend.raw;
84 }
85 return quotient.raw;
86}
87
89{
90 assert(b != 0 && "Division by zero in __divti3");
91
92 int128_t sign = 1;
93 if (a < 0)
94 {
95 sign = -sign;
96 a = -a;
97 }
98 if (b < 0)
99 {
100 sign = -sign;
101 b = -b;
102 }
103
104 uint128_t ua = (uint128_t)a;
105 uint128_t ub = (uint128_t)b;
106 uint128_t uq = __udivmodti4(ua, ub, NULL);
107
108 return (int128_t)uq * sign;
109}
#define assert(expression)
Definition assert.h:29
#define NULL
Pointer error value.
Definition NULL.h:23
static uint64_t __div128_64(uint64_t high, uint64_t low, uint64_t divisor, uint64_t *remainder)
Definition int128.c:25
static int32_t __distance(uint128_split_t a, uint128_split_t b)
Definition int128.c:18
int128_t __divti3(int128_t a, int128_t b)
Definition int128.c:88
uint128_t __udivmodti4(uint128_t a, uint128_t b, uint128_t *c)
Definition int128.c:32
double remainder(double x, double y)
__INT32_TYPE__ int32_t
Definition stdint.h:14
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__uint128_t uint128_t
Definition stdint.h:170
__int128_t int128_t
Definition stdint.h:169
uint64_t low
Definition int128.c:13
uint128_t raw
Definition int128.c:10
uint64_t high
Definition int128.c:14