bitart: Use wrapping integers to prevent overflow

Dividing i64::MIN by -1 can overflow, and reverse_bits made that
likely enough to actually happen.
This commit is contained in:
Juergen Stuber
2026-03-18 18:39:49 +01:00
parent 2b73e0e6b5
commit bd28af4eae
2 changed files with 21 additions and 17 deletions

View File

@@ -1,9 +1,12 @@
use core::fmt; use core::fmt;
use std::num::Wrapping;
use std::rc::Rc; use std::rc::Rc;
use rand::Rng; use rand::Rng;
type Value = Wrapping<i64>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Env { pub struct Env {
pub x: i64, pub x: i64,
@@ -13,8 +16,8 @@ pub struct Env {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Literal(i64); pub struct Literal(i64);
impl Literal { impl Literal {
fn eval(&self) -> i64 { fn eval(&self) -> Value {
self.0 Wrapping(self.0)
} }
} }
impl fmt::Display for Literal { impl fmt::Display for Literal {
@@ -36,10 +39,10 @@ impl Variable {
let i = rng.random_range(0..values.len()); let i = rng.random_range(0..values.len());
values[i] values[i]
} }
fn eval(&self, env: &Env) -> i64 { fn eval(&self, env: &Env) -> Value {
match self { match self {
Variable::X => env.x, Variable::X => Wrapping(env.x),
Variable::Y => env.y, Variable::Y => Wrapping(env.y),
} }
} }
} }
@@ -71,7 +74,7 @@ impl UnaryOperator {
let i = rng.random_range(0..values.len()); let i = rng.random_range(0..values.len());
values[i] values[i]
} }
fn apply(&self, operand: i64) -> i64 { fn apply(&self, operand: Value) -> Value {
match self { match self {
UnaryOperator::Negation => -operand, UnaryOperator::Negation => -operand,
UnaryOperator::Complement => !operand, UnaryOperator::Complement => !operand,
@@ -96,7 +99,7 @@ pub struct UnaryOperation {
operand: Expression, operand: Expression,
} }
impl UnaryOperation { impl UnaryOperation {
fn eval(&self, env: &Env) -> i64 { fn eval(&self, env: &Env) -> Value {
self.operator.apply(self.operand.eval(env)) self.operator.apply(self.operand.eval(env))
} }
fn contains_var(&self, variable: Variable) -> bool { fn contains_var(&self, variable: Variable) -> bool {
@@ -137,19 +140,19 @@ impl BinaryOperator {
let i = rng.random_range(0..values.len()); let i = rng.random_range(0..values.len());
values[i] values[i]
} }
fn apply(&self, operand0: i64, operand1: i64) -> i64 { fn apply(&self, operand0: Value, operand1: Value) -> Value {
fn safe_div(operand0: i64, operand1: i64) -> i64 { fn safe_div(operand0: Value, operand1: Value) -> Value {
if operand1 != 0 { if operand1 != Wrapping(0) {
operand0 / operand1 operand0 / operand1
} else { } else {
0 Wrapping(0)
} }
} }
fn safe_rem(operand0: i64, operand1: i64) -> i64 { fn safe_rem(operand0: Value, operand1: Value) -> Value {
if operand1 != 0 { if operand1 != Wrapping(0) {
operand0 % operand1 operand0 % operand1
} else { } else {
0 Wrapping(0)
} }
} }
match self { match self {
@@ -185,7 +188,7 @@ pub struct BinaryOperation {
operands: [Expression; 2], operands: [Expression; 2],
} }
impl BinaryOperation { impl BinaryOperation {
fn eval(&self, env: &Env) -> i64 { fn eval(&self, env: &Env) -> Value {
self.operator self.operator
.apply(self.operands[0].eval(env), self.operands[1].eval(env)) .apply(self.operands[0].eval(env), self.operands[1].eval(env))
} }
@@ -211,7 +214,7 @@ pub enum InnerExpression {
BinaryOperation(BinaryOperation), BinaryOperation(BinaryOperation),
} }
impl InnerExpression { impl InnerExpression {
pub fn eval(&self, env: &Env) -> i64 { pub fn eval(&self, env: &Env) -> Value {
match self { match self {
InnerExpression::Literal(literal) => literal.eval(), InnerExpression::Literal(literal) => literal.eval(),
InnerExpression::Variable(variable) => variable.eval(env), InnerExpression::Variable(variable) => variable.eval(env),

View File

@@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::env::args; use std::env::args;
use std::io::stdout; use std::io::stdout;
use std::io::Write; use std::io::Write;
use std::num::Wrapping;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
@@ -138,7 +139,7 @@ fn main() -> std::io::Result<()> {
// Find the most common value and its count. // Find the most common value and its count.
let mut max_count = 0; let mut max_count = 0;
let mut max_count_value = 0; let mut max_count_value = Wrapping(0);
for (value, count) in histogram { for (value, count) in histogram {
if count > max_count { if count > max_count {
max_count = count; max_count = count;