mirror of
https://github.com/google/pebble.git
synced 2025-05-14 08:12:19 +00:00
95 lines
2.7 KiB
C
95 lines
2.7 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "util/math.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
int32_t sign_extend(uint32_t a, int bits) {
|
|
if (bits == 32) {
|
|
return a;
|
|
}
|
|
|
|
// http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
|
int const m = 1U << (bits - 1); // mask can be pre-computed if b is fixed
|
|
|
|
a = a & ((1U << bits) - 1); // (Skip this if bits in x above position b are already zero.)
|
|
return (a ^ m) - m;
|
|
}
|
|
|
|
int32_t serial_distance32(uint32_t a, uint32_t b) {
|
|
return serial_distance(a, b, 32);
|
|
}
|
|
|
|
int32_t serial_distance(uint32_t a, uint32_t b, int bits) {
|
|
// See https://en.wikipedia.org/wiki/Serial_Number_Arithmetic
|
|
const int64_t a_minus_b = a - b;
|
|
const int64_t b_minus_a = b - a;
|
|
const bool a_is_earlier_than_b = (a < b && b_minus_a < (1 << (bits - 1))) || (a > b && a_minus_b > (1 << (bits - 1)));
|
|
return sign_extend(a_is_earlier_than_b ? -a_minus_b : b_minus_a, bits);
|
|
}
|
|
|
|
int ceil_log_two(uint32_t n) {
|
|
// clz stands for Count Leading Zeroes. We use it to find the MSB
|
|
int msb = 31 - __builtin_clz(n);
|
|
// popcount counts the number of set bits in a word (1's)
|
|
bool power_of_two = __builtin_popcount(n) == 1;
|
|
// if not exact power of two, use the next power of two
|
|
// we want to err on the side of caution and want to
|
|
// always round up
|
|
return ((power_of_two) ? msb : (msb + 1));
|
|
}
|
|
|
|
//! newton's method for floor(sqrt(x)) -> should always converge
|
|
int32_t integer_sqrt(int64_t x) {
|
|
if (x < 0) {
|
|
return 0;
|
|
}
|
|
int64_t last_res = 0x3fff;
|
|
uint16_t iterations = 0;
|
|
while ((last_res > 0) && (iterations < 15)) {
|
|
last_res = ((x / last_res) + last_res)/2;
|
|
iterations++;
|
|
}
|
|
return (last_res);
|
|
}
|
|
|
|
uint32_t next_exponential_backoff(uint32_t *attempt, uint32_t initial_value, uint32_t max_value) {
|
|
if (*attempt > 31) {
|
|
return max_value;
|
|
}
|
|
uint32_t backoff_multiplier = 0x1 << (*attempt)++;
|
|
uint32_t next_value = initial_value * backoff_multiplier;
|
|
return MIN(next_value, max_value);
|
|
}
|
|
|
|
uint32_t gcd(uint32_t a, uint32_t b) {
|
|
// Infinite loops are bad
|
|
if (a == 0 || b == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Euclidean algorithm, yay!
|
|
while (a != b) {
|
|
if (a > b) {
|
|
a -= b;
|
|
} else {
|
|
b -= a;
|
|
}
|
|
}
|
|
return a;
|
|
}
|