This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#include <stdint.h>
|
||||
#endif // !__KERNEL__
|
||||
|
||||
/**
|
||||
* [Yeetmouse](https://github.com/AndyFilter/YeetMouse/blob/master/driver/FixedMath/Fixed64.h#L1360)
|
||||
* has better string utils. FP64_ToString there doesn't require
|
||||
* `__udivmodti4` in 64-bit mode.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef int32_t FP_INT;
|
||||
typedef int64_t FP_LONG;
|
||||
|
||||
#define FP64_Shift 32
|
||||
|
||||
static inline FP_LONG FP64_Mul(FP_LONG a, FP_LONG b) {
|
||||
return (FP_LONG)(((__int128_t)a * (__int128_t)b) >> FP64_Shift);
|
||||
}
|
||||
|
||||
static char *FP_64_itoa_loop(char *buf, uint64_t scale, uint64_t value,
|
||||
int skip) {
|
||||
while (scale) {
|
||||
unsigned digit = (value / scale);
|
||||
|
||||
if (!skip || digit || scale == 1) {
|
||||
skip = 0;
|
||||
*buf++ = '0' + digit;
|
||||
value %= scale;
|
||||
}
|
||||
|
||||
scale /= 10;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void FP64_ToString(FP_LONG value, char *buf);
|
||||
|
||||
void FP64_ToString(FP_LONG value, char *buf) {
|
||||
uint64_t uvalue = (value >= 0) ? value : -value;
|
||||
if (value < 0)
|
||||
*buf++ = '-';
|
||||
|
||||
#define SCALE 9
|
||||
|
||||
static const uint64_t FP_64_scales[10] = {
|
||||
/* 18 decimals is enough for full 64bit fixed point precision */
|
||||
1, 10, 100, 1000, 10000,
|
||||
100000, 1000000, 10000000, 100000000, 1000000000};
|
||||
|
||||
/* Separate the integer and decimal parts of the value */
|
||||
uint64_t intpart = uvalue >> 32;
|
||||
uint64_t fracpart = uvalue & 0xFFFFFFFF;
|
||||
uint64_t scale = FP_64_scales[SCALE];
|
||||
fracpart = FP64_Mul(fracpart, scale);
|
||||
|
||||
if (fracpart >= scale) {
|
||||
/* Handle carry from decimal part */
|
||||
intpart++;
|
||||
fracpart -= scale;
|
||||
}
|
||||
|
||||
/* Format integer part */
|
||||
buf = FP_64_itoa_loop(buf, 1000000000, intpart, 1);
|
||||
|
||||
/* Format decimal part (if any) */
|
||||
if (scale != 1) {
|
||||
*buf++ = '.';
|
||||
buf = FP_64_itoa_loop(buf, scale / 10, fracpart, 0);
|
||||
}
|
||||
|
||||
*buf = '\0';
|
||||
}
|
||||
Reference in New Issue
Block a user