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:
@@ -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),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user