1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
#include "tintin.h"
#include <inttypes.h>
#include <math.h>
num_t nmul(num_t x, num_t y)
{
/* old compilers redundantly require an explicit message */
_Static_assert(DENOM < 0x100000000ULL, "DENOM not 32-bit");
num_t xh = x/DENOM;
num_t xl = x%DENOM;
num_t yh = y/DENOM;
num_t yl = y%DENOM;
return xh*yh*DENOM
+ xh*yl
+ xl*yh
+ xl*yl/DENOM;
}
num_t ndiv(num_t x, num_t y)
{
num_t zh = x/y;
#ifdef __SIZEOF_INT128__
__uint128_t rem = ((__uint128_t)(llabs(x)%llabs(y)))*DENOM;
num_t zl = rem/llabs(y) * (((x^y)>=0)?+1:-1);
#else
// 128-bit floats have enough precision, and I don't care enough
// about 32-bit archs to optimize. There's enough overhead
// elsewhere that math calculations are non-critical, anyway.
long double rem = ((long double)(llabs(x)%llabs(y)))*DENOM;
num_t zl = roundl(rem/llabs(y)) * (((x^y)>=0)?+1:-1);
#endif
return zh*DENOM + zl;
}
int num2str(char *buf, num_t v)
{
char *b = buf + sprintf(buf, "%s%"PRId64, (v<0 && v>-DENOM)? "-":"",
(int64_t)(v/DENOM));
unsigned x = llabs(v%DENOM);
if (!x)
return b-buf;
*b++='.';
int dig = 10;
do
{
unsigned r = x/(DENOM/10);
*b++='0'+r;
x=(x-r*(DENOM/10))*10;
} while (x && --dig);
*b=0;
return b-buf;
}
int usecstr(char *buf, timens_t v)
{
if (!(v % NANO))
return sprintf(buf, "%lld", v/NANO);
return sprintf(buf, "%s%lld.%06d", (v<0 && v>-NANO)? "-":"",
v/NANO, abs((int)(v%NANO/1000)));
}
int nsecstr(char *buf, timens_t v)
{
if (!(v % NANO))
return sprintf(buf, "%lld", v/NANO);
return sprintf(buf, "%s%lld.%09d", (v<0 && v>-NANO)? "-":"",
v/NANO, abs((int)(v%NANO)));
}
num_t str2num(const char *str, char **err)
{
num_t xh = strtol(str, err, 10) * DENOM;
if (**err!='.')
return xh;
bool neg = *str=='-';
num_t y = DENOM*1000;
num_t x = 0;
for (str = *err+1; isadigit(*str); str++)
{
x += y * (*str-'0');
y/=10;
}
x = (x+4999)/10000;
*err = (char*)str;
return neg? xh-x : xh+x;
}
/* parse a timestamp */
timens_t str2timens(const char *str, char **err)
{
timens_t t = strtol(str, err, 10) * NANO;
if (**err!='.')
return t;
num_t x = (*str=='-')? -NANO:NANO;
for (str = *err+1; isadigit(*str); str++)
t += (*str-'0') * (x/= 10);
*err = (char*)str;
return t;
}
|