当前位置: 首页 > 知识库问答 >
问题:

为什么Rust中没有任意大小的二进制整数类型?

束福
2023-03-14

Rust有二进制文字、二进制格式化程序和大量整数类型,但没有显式的二进制数字类型。

的确,在通用机器中,无符号整数的预期实现是一个大/小端二进制数。然而,这与高级语言的语法相去甚远。例如,如果我有一个八位二进制数0000 0101,我想在语法上把它当作一个基本的数字类型来处理,我有两个问题:(1)数字的字符表示,和(2)数字的类型声明。如果我决定坚持使用u8,我必须添加一层字符串操作(在Rust中)或一层向量操作(例如在MATLAB中),在这些操作中,数字将按字面形式显示或声明,并且我必须确保二进制表示在u8中转换为其等效形式。在这种情况下,如果这个机制没有上升到语法级别,就无法生成直接语句0000 0101 0000 0111,而这只适用于大小恰好与整数类型一致的二进制类型。

例如,一个假设类型b3,它是一个3位二进制数,在其字段中支持适当的数学运算。至少,这些运算是算术运算,当然是在类型b3上闭合的。(定义类型的人必须定义如何在实践中实现闭包的约定,例如,通过包装或断言未定义不能在b3中表达的操作的结果。)

这样的二进制类型可以声明为这样的类型,然后以与任何其他数字类型相同的语法方式使用。因此,101 001==110,无需部署位运算符,以及其他附加要求。

如果这些操作在已经被期望以二进制表示为基础的编程语言中看起来平淡无奇,请注意,在类C语言中实现有限字段算术有一些微妙之处:

/* Multiply two numbers in the GF(2^8) finite field defined 
 * by the polynomial x^8 + x^4 + x^3 + x + 1 = 0
 * using the Russian Peasant Multiplication algorithm
 * (the other way being to do carry-less multiplication followed by a modular reduction)
 */
uint8_t gmul(uint8_t a, uint8_t b) {
    uint8_t p = 0; /* the product of the multiplication */
    while (b) {
        if (b & 1) /* if b is odd, then add the corresponding a to p (final product = sum of all a's corresponding to odd b's) */
            p ^= a; /* since we're in GF(2^m), addition is an XOR */

        if (a & 0x80) /* GF modulo: if a >= 128, then it will overflow when shifted left, so reduce */
            a = (a << 1) ^ 0x11b; /* XOR with the primitive polynomial x^8 + x^4 + x^3 + x + 1 (0b1_0001_1011) – you can change it but it must be irreducible */
        else
            a <<= 1; /* equivalent to a*2 */
        b >>= 1; /* equivalent to b // 2 */
    }
    return p;
}

对于b8来说,一个实现了上述特性的锈菌类型将把所有这些都分解为Mul,这在我看来是锈菌的一个重要特性。能够使用比位掩码和移位更正式、更标准的接口来引用b8数字的特征,这似乎也是Rust可以提供的一个有用的功能。

核心或板条箱中没有这种类型的原因是什么?


共有1个答案

宗政功
2023-03-14

诚恳地说,也许我们都同意这里没有人疯了(?),我实现了一个板条箱,它试图捕获Rust中有限字段的语义,而不受语言或硬件的潜在期望的影响。我必须警告你,它既没有经过严格测试,也没有得到有效实现,但它是编译的,它的示例也是编译的。

它提供以下语义学:

>

#![allow(non_camel_case_types)]
#[macro_use] extern crate finite_fields;

binary_type! { b2, 2 }

该宏扩展为携带数组的newtype结构的实现:

/// A binary number ($fieldwidth digits).
#[derive(Clone, Copy, PartialEq)]
pub struct $tyname([b1; $fieldwidth]);

impl $tyname {
  pub fn new(vals: [b1; $fieldwidth]) -> $tyname {
    $tyname(vals)
  }
} // ...

定义的类型允许通常的算术运算,饱和时有溢出错误,并且被零除错误。具体来说,我在宏中的“单位”n元类型上实现了排序添加位异或索引,以及索引输出,然后将它们用作宏生成的较大n元数的位数。

/// Arithmetic addition with overflow error.
impl Add for $tyname {
  type Output = Result<$tyname, OverflowError>;
  fn add(self, other: $tyname) -> Result<$tyname, OverflowError> {
    let sum = self.0 + other.0;
    if sum > $arity - 1 {
      Err(OverflowError::Default { arg1: self.to_string(),
                                   arg2: other.to_string() })
    } else {
      Ok($tyname(sum as $storsize))
    }
  }
}

可以定义任意类型的有限字段,但存储类型必须由用户指定,以符合Rust使用的标准类型:

/// Creates a ternary type named `t2`, with a unit type named `t1`, storing each
/// digit in a `u8`, with two digits.
nary_type! { t2, t1, 3, u8, 2 }

这就是我困惑的根源。这个板条箱的实现给出的答案是,是的,您可以将任意有限域语义提升到“自然”级别(即base-10、base-2、base-8和base-16)嵌入到语言和硬件中的数字域(即,如果您认为新类型是类型,您可以假装它们是常规数字类型,并得到您期望的粗糙检查),但是,您仍然需要以存储开销(以及可能无法治愈的计算效率低下)的形式向piper支付费用。我不认为我是唯一一个被离散数学和应用计算机科学之间的本体论断层线绊倒的人,但我不确定这是否重要。

无论如何,您可以使用相同的基本宏做完全愚蠢的事情,例如在base 7中的工作:

/// Creates a septary type named `s3`, with a unit type named `s1`, each digit
/// stored in a `u8`, with three digits.
nary_type! { s3, s1, 7, u8, 3 }

好极了让我们都喝醉了,忘掉发生的一切。

 类似资料:
  • 问题内容: 是否有任何特殊原因为什么不包括这种文字,而允许使用十六进制和八进制格式? 问题答案: Java 7包括它。检查新功能。 例:

  • 我已经阅读了一些答案,并收集了以下用例: 当一个函数s 当一个函数有无限循环时 但是我仍然不清楚为什么我们需要这样定义函数: 如果它的工作方式与此相同(没有感叹号): 同时,为什么我们需要使用

  • 但是,在阅读java源代码时,我注意到在和类中,常量是,而不是Float、Byte、Double、Short和character。 注意,SIZE常量表示用于表示实际值的位数。 编辑:我刚刚注意到,这也适用于相同类的和。

  • 假设你想将一个整数转换为一个二进制和十六进制字符串。例如,将整数 10 转换为十进制字符串表示为 10,或将其字符串表示为二进制 1010。虽然有很多算法来解决这个问题,包括在栈部分讨论的算法,但递归的解决方法非常优雅。 让我们看一个十进制数 769 的具体示例。假设我们有一个对应于前 10 位数的字符序列,例如 convString =“0123456789”。 通过在序列中查找,很容易将小于

  • 问题内容: 我很想念,自API级别1开始就存在于documentaion中(我为应用程序使用7th或2.1版本)。 我已经阅读了这个问题,也指出了这个未命中的地方(尽管它不在问题本身内),但是由于提出了自己计算的解决方案。 我并不懒惰,但是我将一些数据发送到服务器(Java项目),在这里或正在使用它们。只想避免错误。 将不胜感激。 问题答案: 如果您在Java 5 和Java 6上 并排打开Jav

  • 问题内容: 但是,如果用前导零检查Integer,则会发现问题是在jdk7发行之前进行的,因此其研究工作量较小。但是在jdk7中,对整数进行了一些更改和添加。以下是有关jdk7的最新答案。 我有一个代码: 编译时出现错误:整数太大:09 为什么这样做呢? 同样,如果我将代码更改为: 现在输出是10 为什么给输出10而不是12? 问题答案: 开头的数字被认为是八 - 9不是一个八进制数字(但(传统)