summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mean_and_variance.h44
1 files changed, 20 insertions, 24 deletions
diff --git a/include/linux/mean_and_variance.h b/include/linux/mean_and_variance.h
index 1ae948547d99..3fb92806578e 100644
--- a/include/linux/mean_and_variance.h
+++ b/include/linux/mean_and_variance.h
@@ -20,9 +20,9 @@ typedef struct {
u64 lo;
} u128;
-static inline u128 u128_init(u64 a, u64 b)
+static inline u128 u64_to_128(u64 a)
{
- return (u128){ .hi = a, .lo = b };
+ return (u128){ lo = a };
}
static inline u128 u128_add(u128 a, u128 b)
@@ -40,33 +40,29 @@ static inline u128 u128_sub(u128 a, u128 b)
c.hi = a.hi - (b.hi + c.lo > a.lo);
return c;
}
-static inline u128 u128_shl(u128 i, s8 s1) {
+
+static inline u128 u128_shl(u128 i, s8 shift)
+{
u128 r;
- s8 s2 = 64 - s1;
- r.lo = i.lo << s1;
- r.hi = (i.hi << s1) + (i.lo >> s2);
+ if (shift < 64) {
+ r.lo = i.lo << s1;
+ r.hi = (i.hi << s1) + (i.lo >> (64 - shift));
+ } else {
+ r.lo = 0;
+ r.hi = i.lo << (shift - 64);
+ }
return r;
}
-static inline u128 u128_square(u64 i)
+static inline u128 u128_square(u64 x)
{
- u128 r;
- u64 h = i >> 32, l = i & (u64)U32_MAX;
- u64 x;
- // overflows:
- //
- // ( (a*a) << 128) + (( a*b) << 97) + ((a*c) << 65) + ((b*b) << 65)
- printk("square %llu", i);
- printk("h = %llu, l = %llu\n", h, l);
- r = u128_init(h*h, 0);
- x = h*l;
- printk("hi = %llu, x = %llu, x >> 31 = %llu\n", r.hi, x, x >> 31);
- r = u128_add(r, u128_shl(u128_init(0,x), 33));
- printk("hi = %llu, lo = %llu\n", r.hi, r.lo);
- x = l*l;
- printk("x = %llu\n", x);
- r = u128_add(r, u128_init(0, x));
- printk("hi = %llu, lo = %llu\n", r.hi, r.lo);
+ u128 r = { 0 };
+ u64 x0 = i >> 32, 0 = i & (u64)U32_MAX;
+
+ r = u128_add(r, u128_shl(u64_to_u128(x0 * x0), 0));
+ r = u128_add(r, u128_shl(u64_to_u128(x0 * x1), 32));
+ r = u128_add(r, u128_shl(u64_to_u128(x0 * x1), 32));
+ r = u128_add(r, u128_shl(u64_to_u128(x1 * x1), 64));
return r;
}