[toc]

0x1::math64

use 0x1::error;
use 0x1::fixed_point32;

常数

AI注:不能对值0取以2为底的对数。

const EINVALID_ARG_FLOOR_LOG2: u64 = 1;

函数

max

返回两个数中较大的一个。

public fun max(a: u64, b: u64): u64

实现

public fun max(a: u64, b: u64): u64 {
    if (a >= b) a else b
}

min

返回两个数中较小的一个。

public fun min(a: u64, b: u64): u64

实现

public fun min(a: u64, b: u64): u64 {
    if (a < b) a else b
}

average

返回两个数的平均值。

public fun average(a: u64, b: u64): u64

实现

public fun average(a: u64, b: u64): u64 {
    if (a < b) {
        a + (b - a) / 2
    } else {
        b + (a - b) / 2
    }
}

gcd

通过欧几里得算法返回ab的最大公约数。

public fun gcd(a: u64, b: u64): u64

实现

public inline fun gcd(a: u64, b: u64): u64 {
    let (large, small) = if (a > b) (a, b) else (b, a);
    while (small != 0) {
        let tmp = small;
        small = large % small;
        large = tmp;
    };
    large
}

mul_div

通过u128计算a * b / c以防止中间溢出。

public fun mul_div(a: u64, b: u64, c: u64): u64

实现

public inline fun mul_div(a: u64, b: u64, c: u64): u64 {
    assert!(c != 0, std::error::invalid_argument(4));
    (((a as u128) * (b as u128) / (c as u128)) as u64)
}

clamp

x限制在区间[lower, upper]内。

public fun clamp(x: u64, lower: u64, upper: u64): u64

实现

public fun clamp(x: u64, lower: u64, upper: u64): u64 {
    min(upper, max(lower, x))
}

pow

返回ne次幂。

public fun pow(n: u64, e: u64): u64

实现

public fun pow(n: u64, e: u64): u64 {
    if (e == 0) {
        1
    } else {
        let p = 1;
        while (e > 1) {
            if (e % 2 == 1) {
                p = p * n;
            };
            e = e / 2;
            n = n * n;
        };
        p * n
    }
}

floor_log2

返回x的以2为底的对数的向下取整值。

public fun floor_log2(x: u64): u8

实现

public fun floor_log2(x: u64): u8 {
    let res = 0;
    assert!(x != 0, std::error::invalid_argument(EINVALID_ARG_FLOOR_LOG2));
    let n = 32;
    while (n > 0) {
        if (x >= (1 << n)) {
            x = x >> n;
            res = res + n;
        };
        n = n >> 1;
    };
    res
}

log2

计算以2为底的对数。

public fun log2(x: u64): fixed_point32::FixedPoint32

实现

public fun log2(x: u64): FixedPoint32 {
    let integer_part = floor_log2(x);
    // 将x规范化到[1, 2)区间内,以进行定点32位计算。
    let y = (if (x >= 1 << 32) {
        x >> (integer_part - 32)
    } else {
        x << (32 - integer_part)
    } as u128);
    let frac = 0;
    let delta = 1 << 31;
    while (delta != 0) {
        // log x = 1/2 log x^2
        // x在[1, 2)区间内
        y = (y * y) >> 32;
        // 现在x在[1, 4)区间内
        // 如果x在[2, 4)区间内,那么log x = 1 + log (x / 2)
        if (y >= (2 << 32)) { frac = frac + delta; y = y >> 1; };
        delta = delta >> 1;
    };
    fixed_point32::create_from_raw_value (((integer_part as u64) << 32) + frac)
}

sqrt

返回x的平方根,精确到floor(sqrt(x))

public fun sqrt(x: u64): u64

实现

public fun sqrt(x: u64): u64 {
    if (x == 0) return 0;
    let res = 1 << ((floor_log2(x) + 1) >> 1);
    // 使用标准牛顿-拉弗森迭代法改进初始近似值。
    // 误差项演进为delta_i+1 = delta_i^2 / 2(二次收敛)。
    // 经过4次迭代后,delta小于2^-32,因此低于阈值。
    res = (res + x / res) >> 1;
    res = (res + x / res) >> 1;
    res = (res + x / res) >> 1;
    res = (res + x / res) >> 1;
    min(res, x / res)
}

ceil_div

返回x除以y后向上取整的结果。

public fun ceil_div(x: u64, y: u64): u64

实现

public inline fun ceil_div(x: u64, y: u64): u64 {
    // ceil_div(x, y) = floor((x + y - 1) / y) = floor((x - 1) / y) + 1
    // (x + y - 1) 可能会导致错误溢出,因此我们使用后一种版本
    if (x == 0) {
        assert!(y != 0, std::error::invalid_argument(4));
        0
    }
    else (x - 1) / y + 1
}

规格说明

max

public fun max(a: u64, b: u64): u64

如果false,则中止。

确保如果a >= b,则结果为a;如果a < b,则结果为b

min

public fun min(a: u64, b: u64): u64

如果false,则中止。

确保如果a < b,则结果为a;如果a >= b,则结果为b

average

public fun average(a: u64, b: u64): u64

特性 opaque;如果false,则中止。

确保结果为(a + b) / 2

clamp

public fun clamp(x: u64, lower: u64, upper: u64): u64

需要(lower <= upper);如果false,则中止。

确保如果(lower <= x && x <= upper),则结果为x;如果x < lower,则结果为lower;如果upper < x,则结果为upper

pow

public fun pow(n: u64, e: u64): u64

特性 opaque;如果[abstract] spec_pow(n, e) > MAX_U64,则中止。

确保[abstract] result == spec_pow(n, e)

floor_log2

public fun floor_log2(x: u64): u8

特性 opaque;如果[abstract] x == 0,则中止。

确保[abstract] spec_pow(2, result) <= x;确保[abstract] x < spec_pow(2, result+1)

sqrt

public fun sqrt(x: u64): u64

特性 opaque;如果[abstract] false,则中止。

确保如果x > 0,则result * result <= x;确保如果x > 0,则x < (result+1) * (result+1)

spec_pow

fun spec_pow(n: u64, e: u64): u64 {
   if (e == 0) {
       1
   }
   else {
       n * spec_pow(n, e-1)
   }
}