15#ifndef GPUCOMMONDOUBLEBINARY64_H
16#define GPUCOMMONDOUBLEBINARY64_H
18#if !defined(__METAL__) && !defined(GPUCA_B64_HOST_REFERENCE)
19#error "the emulated binary64 is for Metal, which has no double of its own; every other backend has a real one. Define GPUCA_B64_HOST_REFERENCE to build it on the host as a test reference."
23#ifndef GPUCA_GPUCODE_DEVICE
44namespace binary64_detail
57#define GPUCA_B64_ALWAYS inline __attribute__((always_inline))
62#define GPUCA_B64_OP __attribute__((noinline))
64#define GPUCA_B64_OP inline
87 const u64 al =
a & 0xffffffffu, ah =
a >> 32, bl =
b & 0xffffffffu, bh =
b >> 32;
88 const u64 ll = al * bl, lh = al * bh, hl = ah * bl, hh = ah * bh;
89 const u64 mid = (ll >> 32) + (lh & 0xffffffffu) + (hl & 0xffffffffu);
90 return hh + (lh >> 32) + (hl >> 32) + (mid >> 32);
100#define GPUCA_B64_SIGN 0x8000000000000000ULL
101#define GPUCA_B64_FRAC 0x000fffffffffffffULL
102#define GPUCA_B64_IMPL 0x0010000000000000ULL
103#define GPUCA_B64_QUIET 0x0008000000000000ULL
104#define GPUCA_B64_INF 0x7ff0000000000000ULL
105#define GPUCA_B64_DNAN 0x7ff8000000000000ULL
110 const int32_t sc = s > 63 ? 63 : s;
111 const u64 r =
m >> sc;
112 const u64 lost = (
m << (63 - sc)) << 1;
113 const bool big = s > 63;
115 const u64 st = big ?
m : lost;
116 return rr | (
st != 0 ? 1ULL : 0
ULL);
131 const u64 r =
m & 0x3ffULL;
133 if (
r > 0x200ULL || (
r == 0x200ULL && (
m & 1ULL))) {
136 return sign | (((
u64)(e - 1) << 52) +
m);
157 int32_t ex = (int32_t)((
x >> 52) & 0x7ff), ey = (int32_t)((
y >> 52) & 0x7ff);
170 const bool sub = ((
x ^
y) >> 63) != 0;
176 const u64 s = sub ? mx - my : mx + my;
177 const bool carry = (s >> 63) != 0;
178 const int32_t lz =
clz64(s) - 1;
179 const u64 sN = carry ? ((s >> 1) | (s & 1ULL)) : (s << (lz & 63));
180 const int32_t eN = carry ? ex + 1 : ex - lz;
181 const bool zero = s == 0;
182 return roundPack((zero && sub) ? 0
ULL : sx, zero ? -1 : eN, sN);
188 int32_t ea = (int32_t)((
a >> 52) & 0x7ff), eb = (int32_t)((
b >> 52) & 0x7ff);
190 if (ea == 0x7ff || eb == 0x7ff) {
191 const bool an = ea == 0x7ff && ma != 0, bn = eb == 0x7ff && mb != 0;
195 if ((ea == 0 && ma == 0) || (eb == 0 && mb == 0)) {
204 const int32_t lz =
clz64(ma) - 11;
214 const int32_t lz =
clz64(mb) - 11;
220 const u64 lo = ma * mb, hi =
mulhiu(ma, mb);
221 const bool top = (hi & (1ULL << 41)) != 0;
222 const u64 m1 = (hi << 21) | (lo >> 43), m0 = (hi << 22) | (lo >> 42);
223 const u64 st =
top ? (lo & ((1ULL << 43) - 1)) : (lo & ((1ULL << 42) - 1));
224 const u64 m = (
top ? m1 : m0) | (
st != 0 ? 1ULL : 0
ULL);
231 int32_t ea = (int32_t)((
a >> 52) & 0x7ff), eb = (int32_t)((
b >> 52) & 0x7ff);
233 if (ea == 0x7ff || eb == 0x7ff) {
234 const bool an = ea == 0x7ff && ma != 0, bn = eb == 0x7ff && mb != 0;
238 if (ea == 0x7ff && eb == 0x7ff) {
243 if (eb == 0 && mb == 0) {
250 const int32_t lz =
clz64(ma) - 11;
257 const int32_t lz =
clz64(mb) - 11;
263 const bool lt = ma < mb;
264 const int32_t e = ea - eb + 1023 - (lt ? 1 : 0);
265 const u64 A2 = lt ? (ma << 1) : ma;
267 const u32 rb =
asu32(1.0f / (
float)(
u32)(mb >> 29));
268 u64 R = (
u64)((rb & 0x7fffffu) | 0x800000u) << ((int32_t)((rb >> 23) & 0xff) - 127 + 62);
269 const u64 Bn = mb << 11;
270 for (int32_t it = 0; it < 2; ++it) {
274 R =
R > (1ULL << 62) ? (1ULL << 62) :
R;
278 i64 rem = (
i64)((A2 << 62) - Q * mb);
281 rem -= adj * (
i64)mb;
283 const bool ng = rem < 0;
285 rem = ng ? rem + (
i64)mb : rem;
286 const bool bg = rem >= (
i64)mb;
288 rem = bg ? rem - (
i64)mb : rem;
289 return roundPack(sign, e, Q | (rem != 0 ? 1ULL : 0
ULL));
298 const int32_t lz =
clz32(
x);
310 const u64 sign = (
u64)(u & 0x80000000u) << 32;
311 int32_t e = (int32_t)((u >> 23) & 0xff);
312 u32 m = u & 0x7fffffu;
320 const int32_t lz =
clz32(
m) - 8;
324 return sign | ((
u64)(e - 127 + 1023) << 52) | ((
u64)(
m & 0x7fffffu) << 29);
330 const u32 sign = (
u32)(d >> 32) & 0x80000000u;
331 const int32_t be = (int32_t)((d >> 52) & 0x7ff);
333 const u32 drop = (
u32)d & 0x1fffffffu;
337 }
else if (be == 0) {
340 const int32_t e = be - 1023 + 127;
342 bits = sign | 0x7f800000u;
344 bits = sign | ((
u32)e << 23) | man;
345 if ((drop & 0x10000000u) && ((drop & 0x0fffffffu) || (man & 1u))) {
348 }
else if (e > -24) {
349 const u32 full = man | 0x800000u;
350 const u32 sh = (
u32)(1 - e);
351 const u32 lost = full & ((1u << sh) - 1u);
352 const u32 halfb = 1u << (sh - 1);
353 u32 sub = full >> sh;
354 if (lost > halfb || (lost == halfb && ((sub & 1u) || drop))) {
383 GPUdi() constexpr GPUdoubleBinary64 operator+(
float b)
const {
return *
this + GPUdoubleBinary64(
b); }
384 GPUdi() constexpr GPUdoubleBinary64 operator-(
float b)
const {
return *
this - GPUdoubleBinary64(
b); }
385 GPUdi() constexpr GPUdoubleBinary64 operator*(
float b)
const {
return *
this * GPUdoubleBinary64(
b); }
386 GPUdi() constexpr GPUdoubleBinary64 operator/(
float b)
const {
return *
this / GPUdoubleBinary64(
b); }
388 GPUdi() constexpr GPUdoubleBinary64 operator+(
double b)
const {
return *
this + (float)
b; }
389 GPUdi() constexpr GPUdoubleBinary64 operator-(
double b)
const {
return *
this - (float)
b; }
390 GPUdi() constexpr GPUdoubleBinary64 operator*(
double b)
const {
return *
this * (float)
b; }
391 GPUdi() constexpr GPUdoubleBinary64 operator/(
double b)
const {
return *
this / (float)
b; }
407 GPUdi() constexpr GPUdoubleBinary64(
float v) constant :
mBits(binary64_detail::fromFloat(
v)) {}
413 GPUdi() constexpr GPUdoubleBinary64 operator+(
float b) constant {
return *
this + GPUdoubleBinary64(
b); }
414 GPUdi() constexpr GPUdoubleBinary64 operator-(
float b) constant {
return *
this - GPUdoubleBinary64(
b); }
415 GPUdi() constexpr GPUdoubleBinary64 operator*(
float b) constant {
return *
this * GPUdoubleBinary64(
b); }
416 GPUdi() constexpr GPUdoubleBinary64 operator/(
float b) constant {
return *
this / GPUdoubleBinary64(
b); }
421 GPUdi() GPUdoubleBinary64& operator+=(GPUdoubleBinary64
b) {
return *
this = *
this +
b; }
424 GPUdi() GPUdoubleBinary64& operator/=(GPUdoubleBinary64
b) {
return *
this = *
this /
b; }
434static_assert(
sizeof(
GPUdoubleBinary64) == 8,
"the emulated double must match the size of a real one");
435static_assert(
alignof(
GPUdoubleBinary64) == 8,
"the emulated double must match the alignment of a real one");
445GPUdi() constexpr GPUdoubleBinary64 operator+(
float a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64(
a) +
b; }
446GPUdi() constexpr GPUdoubleBinary64 operator-(
float a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64(
a) -
b; }
447GPUdi() constexpr GPUdoubleBinary64 operator*(
float a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64(
a) *
b; }
448GPUdi() constexpr GPUdoubleBinary64 operator/(
float a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64(
a) /
b; }
450GPUdi() constexpr GPUdoubleBinary64 operator+(
double a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64((
float)
a) +
b; }
451GPUdi() constexpr GPUdoubleBinary64 operator-(
double a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64((
float)
a) -
b; }
452GPUdi() constexpr GPUdoubleBinary64 operator*(
double a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64((
float)
a) *
b; }
453GPUdi() constexpr GPUdoubleBinary64 operator/(
double a, GPUdoubleBinary64
b) {
return GPUdoubleBinary64((
float)
a) /
b; }
458GPUdi() thread
float& operator+=(thread
float&
a, GPUdoubleBinary64
b) {
return a = (float)(GPUdoubleBinary64(
a) +
b); }
459GPUdi() device
float& operator+=(device
float&
a, GPUdoubleBinary64
b) {
return a = (float)(GPUdoubleBinary64(
a) +
b); }
460GPUdi() threadgroup
float& operator+=(threadgroup
float&
a, GPUdoubleBinary64
b) {
return a = (float)(GPUdoubleBinary64(
a) +
b); }
462GPUdi() float& operator+=(
float&
a, GPUdoubleBinary64
b) {
return a = (float)(GPUdoubleBinary64(
a) +
b); }
465namespace binary64_detail
471GPUCA_B64_OP GPUdoubleBinary64 kernelSin(GPUdoubleBinary64
x, GPUdoubleBinary64
y,
bool iy)
473 typedef GPUdoubleBinary64 b64;
474 const b64 S1 = b64::fromBits(0xBFC5555555555549ULL);
475 const b64 S2 = b64::fromBits(0x3F8111111110F8A6ULL);
476 const b64 S3 = b64::fromBits(0xBF2A01A019C161D5ULL);
477 const b64 S4 = b64::fromBits(0x3EC71DE357B1FE7DULL);
478 const b64 S5 = b64::fromBits(0xBE5AE5E68A2B9CEBULL);
479 const b64 S6 = b64::fromBits(0x3DE5D93A5ACFD57CULL);
482 const b64
r = S2 +
z * (S3 +
z * (S4 +
z * (S5 +
z * S6)));
484 return x +
v * (S1 +
z *
r);
486 return x - ((
z * (b64::fromBits(0x3FE0000000000000ULL) *
y -
v *
r) -
y) -
v * S1);
489GPUCA_B64_OP GPUdoubleBinary64 kernelCos(GPUdoubleBinary64
x, GPUdoubleBinary64
y)
491 typedef GPUdoubleBinary64 b64;
492 const b64 C1 = b64::fromBits(0x3FA555555555554CULL);
493 const b64 C2 = b64::fromBits(0xBF56C16C16C15177ULL);
494 const b64 C3 = b64::fromBits(0x3EFA01A019CB1590ULL);
495 const b64 C4 = b64::fromBits(0xBE927E4F809C52ADULL);
496 const b64 C5 = b64::fromBits(0x3E21EE9EBDB4B1C4ULL);
497 const b64 C6 = b64::fromBits(0xBDA8FAE9BE8838D4ULL);
498 const b64
one = b64::fromBits(0x3FF0000000000000ULL);
499 const b64 oneHalf = b64::fromBits(0x3FE0000000000000ULL);
500 const u32 ix = (
u32)(
x.bits() >> 32) & 0x7fffffffu;
502 const b64
r =
z * (C1 +
z * (C2 +
z * (C3 +
z * (C4 +
z * (C5 +
z * C6)))));
503 if (ix < 0x3FD33333u) {
504 return one - (oneHalf *
z - (
z *
r -
x *
y));
506 const b64 qx = (
ix > 0x3FE90000u) ? b64::fromBits(0x3FD2000000000000ULL) : b64::fromBits((
u64)(ix - 0x00200000u) << 32);
507 return (
one - qx) - ((oneHalf *
z - qx) - (
z *
r -
x *
y));
512 const u64 b =
x.bits();
513 const int32_t e = (int32_t)((
b >> 52) & 0x7ff) - 1023;
518 const int32_t
v = (int32_t)(e >= 52 ? (
m << (e - 52)) : (
m >> (52 - e)));
523 GPUdoubleBinary64
s,
c;
528 typedef GPUdoubleBinary64 b64;
529 const u32 ix = (
u32)(
x.bits() >> 32) & 0x7fffffffu;
531 if (ix >= 0x7FF00000u) {
536 if (ix < 0x3E400000u) {
538 out.c = b64::fromBits(0x3FF0000000000000ULL);
542 b64
y0 =
x,
y1 = b64::fromBits(0
ULL);
544 const bool reduced =
ix > 0x3FE921FBu;
547 n = truncToInt32(t * b64::fromBits(0x3FE45F306DC9C883ULL) + b64::fromBits(0x3FE0000000000000ULL));
548 const b64 fn = b64((
float)
n);
550 b64
r = t - fn * b64::fromBits(0x3FF921FB54400000ULL);
552 b64
w = fn * b64::fromBits(0x3DD0B4611A600000ULL);
554 w = fn * b64::fromBits(0x3BA3198A2E037073ULL) - ((
s -
r) -
w);
556 w = fn * b64::fromBits(0x3BA3198A2E000000ULL);
558 w = fn * b64::fromBits(0x397B839A252049C1ULL) - ((
s -
r) -
w);
570 out.s = kernelSin(
y0,
y1, reduced);
571 out.c = kernelCos(
y0,
y1);
574 out.s = kernelCos(
y0,
y1);
575 out.c = -kernelSin(
y0,
y1, reduced);
578 out.s = -kernelSin(
y0,
y1, reduced);
579 out.c = -kernelCos(
y0,
y1);
582 out.s = -kernelCos(
y0,
y1);
583 out.c = kernelSin(
y0,
y1, reduced);
Class for time synchronization of RawReader instances.
binary64_detail::u64 mBits
GPUdi() static const expr GPUdoubleBinary64 fromBits(binary64_detail
GPUdi() const expr operator float() const
GPUdi() const expr binary64_detail
GPUdDefault() GPUdoubleBinary64()=default
GPUdi() const expr GPUdoubleBinary64(binary64_detail
GPUdi() const expr GPUdoubleBinary64(float v)
GPUdi() GPUdoubleBinary64 &operator-
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLdouble GLdouble GLdouble GLdouble top
GLboolean GLboolean GLboolean b
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLuint GLfloat GLfloat y0
GLdouble GLdouble GLdouble z
GPUCA_B64_OP constexpr u64 addsub(u64 a, u64 b0, bool neg)
GPUCA_B64_OP constexpr float toFloat(u64 d)
GPUCA_B64_ALWAYS constexpr u64 propNaN(u64 a, u64 b, bool an, bool bn)
GPUCA_B64_ALWAYS constexpr u64 mulhiu(u64 a, u64 b)
GPUCA_B64_ALWAYS constexpr u64 fromI32(int32_t x)
GPUCA_B64_ALWAYS constexpr int32_t clz64(u64 x)
GPUCA_B64_ALWAYS constexpr i64 mulhis(i64 a, i64 b)
GPUCA_B64_ALWAYS constexpr u64 shrJam(u64 m, int32_t s)
GPUCA_B64_OP constexpr u64 div(u64 a, u64 b)
GPUCA_B64_ALWAYS constexpr u64 roundPack(u64 sign, int32_t e, u64 m)
GPUCA_B64_ALWAYS constexpr float asf32(u32 u)
GPUCA_B64_ALWAYS constexpr int32_t clz32(u32 x)
GPUCA_B64_ALWAYS constexpr u64 fromFloat(float f)
GPUCA_B64_OP constexpr u64 mul(u64 a, u64 b)
GPUCA_B64_ALWAYS constexpr u32 asu32(float f)
GPUCA_B64_ALWAYS constexpr u64 fromU32(u32 x)