Rust 整数和浮点数支持的 API

楔子

前面介绍了 Rust 的类型,比如整数、浮点数、数组等等,但我们仅仅是知道这些数据结构,而它们所拥有的方法我们还不是很清楚。在工作中光有数据结构也不够,如果不知道它提供的一系列方法,我们就无法对数据做处理。所以接下来的几篇文章,我们就来看这些数据结构都有哪些方法。

首先从整数和浮点数开始。

整数所拥有的方法

整数是非常简单的数据结构,但它拥有的方法也不少。

MIN:获取指定整数类型的最小值

MAX:获取指定整数类型的最大值

fn main() {
    println!("{} {}", i8::MIN, i8::MAX);
    println!("{} {}", u16::MIN, u16::MAX);
    println!("{} {}", i32::MIN, i32::MAX);
    /*
    -128 127
    0 65535
    -2147483648 2147483647
    */
}

BITS:获取指定整数类型的位数

fn main() {
    println!("{} {}", i8::BITS, u32::BITS);  // 8 32
}

from_str_radix:将字符串切片转成整数

fn main() {
    // i16::from_str_radix 返回 Result<i16, ParseIntError>
    // 第一个参数是字符串切片,第二个参数是进制
    println!("{:?}", i16::from_str_radix("123", 10));  // Ok(123)
    println!("{:?}", u32::from_str_radix("123", 10));  // Ok(123)

    println!("{:?}", u32::from_str_radix("111", 2));  // Ok(7)
    println!("{:?}", u32::from_str_radix("FFFF", 16));  // Ok(65535)

    println!("{:?}", u32::from_str_radix("abc", 16));  // Ok(2748)
    println!("{:?}", i64::from_str_radix("abc", 10));  // Err(ParseIntError { kind: InvalidDigit })
}

当然,里面包含正负号也是可以解析的。

fn main() {
    println!("{:?}", i16::from_str_radix("+123", 10));  // Ok(123)
    println!("{:?}", i32::from_str_radix("-123", 10));  // Ok(-123)
    // u32 无法解析负数
    println!("{:?}", u32::from_str_radix("-123", 10));  // Err(ParseIntError { kind: InvalidDigit })
}

to_string:将整数转成字符串(String)

fn main() {
    println!("{}", 123.to_string());  // 123
}

count_ones:返回整数对应的二进制中有多少个 1

count_zeros:返回整数对应的二进制中有多少个 0

fn main() {
    let n: i32 = 0b101101001;
    println!("{:?}", n.count_ones());  // 5
    // n 是 32 位整数,1 有 5 个,所以 0 有 27 个
    println!("{:?}", n.count_zeros());  // 27
}

leading_zeros:返回整数对应的二进制中前导 0 的个数

fn main() {
    let n: i32 = 0b101101001;
    println!("{:?}", n.count_zeros());  // 27
    // 从最高位往右数,直到遇见第一个不是 0
    println!("{:?}", n.leading_zeros());  // 23
    // 从最低位往左数,直到遇见第一个不是 0
    println!("{:?}", n.trailing_zeros());  // 0
    // 从最高位往右数,直到遇见第一个不是 1
    println!("{:?}", n.leading_ones());  // 0
    // 从最低位往左数,直到遇见第一个不是 1
    println!("{:?}", n.trailing_ones());  // 1
}

rotate_left:左移 n 个位,将截断的 n 个位拼接到整数的末尾

fn main() {
    let n: u8 = 0b1011_1111;
    // 左移 2 两位(显然高位的 10 会被阶段),将其拼接到末尾,所以结果是 0b1111_1110
    println!("{} {}", n.rotate_left(2), 0b1111_1110); // 254 254
    // 注意:这和左移不同,如果是左移,那么会在低位补 0
    // rotate_left 是将截断的位拼接在整数的尾部
    print!("{} {}", n << 2, 0b1111_1100);  // 252 252
}

同理还有 rotate_right,右移 n 个位,并将截断的 n 个位拼接到整数的开头。

reverse_bits:将整数的位进行反转,低位变高位,高位变低位

fn main() {
    let n: u8 = 0b1111_0000;
    println!("{} {}", n.reverse_bits(), 0b0000_1111); // 254 254
}

overflowing_add:加法运算,当溢出时进行环绕

fn main() {
    let n: u8 = 255;
    // n + 10 会出现溢出,所以采用 overflowing_add,当溢出时进行环绕
    // 如果 n + 10 > u8::MAX,那么结果为 (n + 10) - 2 ^ 8
    let (result, ok) = n.overflowing_add(10);
    // 如果溢出,ok 为 true,否则为 false
    println!("{} {}", result, (n as u16 + 10) - 256); // 9 9
}

同理还有overflowing_sub、overflowing_mul、overflowing_div。

ilog:计算对数

fn main() {
    let n: u8 = 255;
    println!("{}", n.ilog(15));  // 2
    // 如果底数为 2,那么可以使用 ilog2,底数为 10,可以使用 ilog10
    println!("{} {}", 16u8.ilog2(), 1000u32.ilog10());  // 4 3
}

abs:获取整数的绝对值

fn main() {
    let n: i32 = -255;
    println!("{}", n.abs());  // 255
}

pow:获取整数的 n 次幂

fn main() {
    println!("{}", 2i32.pow(4));  // 16
}

以上就是整数所拥有的一系列方法,当然还有很多其它方法,不过不常用,有兴趣可以查看官网。

浮点数所拥有的方法

看完了整数,再来看看浮点数。需要先说明的是,有很多的我们常见的方法,比如求对数、求平方根等等,这些方法整数是没有的,但浮点数有。所以如果整数想使用这些方法,需要先转成浮点数。

整数和浮点数的相互转化

fn main() {
    println!("{} {}", 3.14 as i32, 123 as f64);  // 3 123
    println!("{} {}", -3.14 as i32, -123 as f64);  // -3 -123
}

floor:向下取整,返回浮点数

fn main() {
    println!("{} {}", 4.2f32.floor(), (-4.2f32).floor())  // 4 -5
}

ceil:向上取整,返回浮点数

fn main() {
    println!("{} {}", 4.2f32.ceil(), (-4.2f32).ceil())  // 5 -4
}

round:四舍五入,返回浮点数

fn main() {
    // 这里补充一点,由于 f32 和 f64 的方法是相同的
    // 所以通过字面量来调用的话,Rust 不知道字面量的类型,所以需要显式指定
    println!("{}", 3.3333f64.round());  // 3
    println!("{}", 3.5333f64.round());  // 4
}

trunc:截断,返回浮点数,注意它和 floor 的差别

fn main() {
    let f = 3.7_f32;
    let g = 3.0_f32;
    let h = -3.7_f32;

    println!("{} {}", f.trunc(), f.floor());  // 3 3
    println!("{} {}", g.trunc(), g.floor());  // 3 3
    println!("{} {}", h.trunc(), h.floor());  // -3 -4
    // trunc 和 as 的作用比较类似
    println!("{} {}", f as i32, h as i32);  // 3 -3
}

fract:返回浮点数的小数部分

fn main() {
    let x = 3.6_f32;
    let y = -3.6_f32;
    println!("{} {}", x.fract(), y.fract())  // 0.5999999 -0.5999999
}

abs:返回浮点数的绝对值

fn main() {
    let x = 3.6_f32;
    let y = -3.6_f32;
    println!("{} {}", x.abs(), y.abs())  // 3.6 3.6
}

signum:返回浮点数的符号(浮点数),大于等于 0 返回 1,负数返回 -1

fn main() {
    let x = 3.6_f32;
    let y = -3.6_f32;
    println!("{} {} {}", x.signum(), y.signum(), 0.0f32.signum())  // 1 0 1
}

copysign:将另一个浮点数的符号 copy 到当前浮点数上

fn main() {
    let x = 3.6_f32;
    let y = -3.6_f32;
    println!("{} {}", x.copysign(0.0f32), x.copysign(-0.0f32));  // 3.6 -3.6
    println!("{} {}", y.copysign(0.0f32), y.copysign(-0.0f32));  // 3.6 -3.6
}

powi:计算一个浮点数的 n 次幂,n 为整数,返回浮点数

fn main() {
    println!("{}", 2f32.powi(4));  // 16
}

sqrt:计算一个浮点数的平方根,返回浮点数

fn main() {
    let n = 10000;
    println!("{}", (n as f32).sqrt() as i32);  // 100

    // 还可以返回一个数的立方根
    let n = 1000;
    println!("{}", (n as f32).cbrt())  // 10
}

exp:以 e 为底,计算一个浮点数的指数运算,返回浮点数

fn main() {
    let n = 1;
    println!("{}", (n as f32).exp());  // 2.7182817
    // 以 2 为底
    println!("{}", (n as f32).exp2());  // 2
}

log:计算一个浮点数的对数,返回浮点数

use std::f64::consts::E;

fn main() {
    let n = 1024i32;
    // 整数的 ilog 方法接收一个整数作为底数,并且底数的类型和整数一致,返回值也是整数
    // 浮点数的 log 方法接收一个浮点数作为底数,并且底数的类型和浮点数一致,返回值也是浮点数
    println!("{} {}", n.ilog(2), (n as f32).log(2f32));   // 10 10

    let n = 1023i32;
    println!("{} {}", n.ilog(2), (n as f32).log(2f32));   // 9 9.99859

    // int.ilog(2) 和 int.ilog(10) 可以换成 int.ilog2() 和 int.ilog10()
    // float.log(2) 和 float.log(10) 可以换成 float.log2() 和 float.log10()

    // 此外浮点数还提供了一个方法,针对自然对数
    println!("{} {}", E.ln(), E.log(E))  // 1 1
}

hypot:计算两个点,返回浮点数组成的坐标和原点的距离,返回浮点数

fn main() {
    println!("{} {}", 3f32.hypot(4f32), 6f32.hypot(8f32));  // 5 10
}

下面是一些三角函数,它们返回的都是浮点数

  • sin:正弦值
  • cos:余弦值
  • tan:正切值
  • asin:反正弦值
  • acos:反余弦值
  • atan:反正切值
  • sinh:双曲正弦值
  • cosh:双曲余弦值
  • tanh:双曲正切值
  • asinh:反双曲正弦值
  • acosh:反双曲余弦值
  • atanh:反双曲正切值
use std::f32::consts::PI;

fn main() {
    // sin:正弦(对边比斜边),csc:余割(斜边比对边)
    // 如果 f(x) = sin(x),那么 1 / sin(x) 得到的就是 csc(x)
    println!("{}", (PI / 6f32).sin());  // 0.5
    println!("{} {}", (PI / 3.0).sin(), (3f32.sqrt() / 2.0));  // 0.86602545 0.8660254

    // cos:余弦(斜边比邻边),sec:正割(邻边比斜边)
    // 如果 f(x) = cos(x),那么 1 / cos(x) 得到的就是 sec(x)
    println!("{}", (PI / 3f32).cos());  // 0.49999997

    // tan:正切(对边比邻边),cot:余切(领边比对边)
    // 如果 f(x) = tan(x),那么 1 / tan(x) 得到的就是 cot(x)
    println!("{}", (PI / 4f32).tan());  // 1

    // 对于两个函数:y = f(x) 和 y = g(x)
    // 对于任意一点 (a, b) 如果同时满足 b = f(a) 且 a = g(b),那么 f(x) 和 g(x) 互为反函数
    // 比如 sin 和 asin 互为反函数,已知 sin(pi / 6) = 1 / 2,那么 asin(1 / 2) = pi / 6
    println!("{} {}", (1f32 / 2f32).asin(), PI / 6f32);  // 0.5235988 0.5235988
}

NAN、INFINITY

fn main() {
    println!("{}", f32::NAN.is_nan());  // true
    println!("{}", f32::INFINITY.is_infinite());  // true
    // 如果浮点数即不是 NAN 也不是 INFINITY,返回 true
    println!("{}", 3.14f32.is_finite());  // true
}

角度和弧度互转

fn main() {
    // 返回的均是浮点数
    println!("{}", std::f64::consts::PI.to_degrees());  // 180
    println!("{}", 180f32.to_radians());  // 3.1415927
}

获取两个浮点数中的大的和小的那一个

fn main() {
    let x = 3f32;
    let y = 4f32;
    println!("{} {}", x.max(y), if x > y {x} else {y});  // 4 4
    println!("{} {}", x.min(y), if x < y {x} else {y});  // 3 3
}

以上就是整数和浮点数支持的一些方法。

posted @ 2023-10-23 15:32  古明地盆  阅读(304)  评论(0编辑  收藏  举报