Files
IronCalc/base/src/functions/engineering/bit_operations.rs
2024-02-20 15:19:05 +01:00

233 lines
7.3 KiB
Rust

use crate::{
calc_result::CalcResult,
expressions::{parser::Node, token::Error, types::CellReferenceIndex},
model::Model,
};
// 2^48-1
const MAX: f64 = 281474976710655.0;
impl Model {
// BITAND( number1, number2)
pub(crate) fn fn_bitand(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 2 {
return CalcResult::new_args_number_error(cell);
}
let number1 = match self.get_number(&args[0], cell) {
Ok(f) => f,
Err(s) => return s,
};
let number2 = match self.get_number(&args[1], cell) {
Ok(f) => f,
Err(s) => return s,
};
if number1.trunc() != number1 || number2.trunc() != number2 {
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
}
if number1 < 0.0 || number2 < 0.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be positive or zero".to_string(),
);
}
if number1 > MAX || number2 > MAX {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be less than 2^48-1".to_string(),
);
}
let number1 = number1.trunc() as i64;
let number2 = number2.trunc() as i64;
let result = number1 & number2;
CalcResult::Number(result as f64)
}
// BITOR(number1, number2)
pub(crate) fn fn_bitor(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 2 {
return CalcResult::new_args_number_error(cell);
}
let number1 = match self.get_number(&args[0], cell) {
Ok(f) => f,
Err(s) => return s,
};
let number2 = match self.get_number(&args[1], cell) {
Ok(f) => f,
Err(s) => return s,
};
if number1.trunc() != number1 || number2.trunc() != number2 {
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
}
if number1 < 0.0 || number2 < 0.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be positive or zero".to_string(),
);
}
if number1 > MAX || number2 > MAX {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be less than 2^48-1".to_string(),
);
}
let number1 = number1.trunc() as i64;
let number2 = number2.trunc() as i64;
let result = number1 | number2;
CalcResult::Number(result as f64)
}
// BITXOR(number1, number2)
pub(crate) fn fn_bitxor(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 2 {
return CalcResult::new_args_number_error(cell);
}
let number1 = match self.get_number(&args[0], cell) {
Ok(f) => f,
Err(s) => return s,
};
let number2 = match self.get_number(&args[1], cell) {
Ok(f) => f,
Err(s) => return s,
};
if number1.trunc() != number1 || number2.trunc() != number2 {
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
}
if number1 < 0.0 || number2 < 0.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be positive or zero".to_string(),
);
}
if number1 > MAX || number2 > MAX {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be less than 2^48-1".to_string(),
);
}
let number1 = number1.trunc() as i64;
let number2 = number2.trunc() as i64;
let result = number1 ^ number2;
CalcResult::Number(result as f64)
}
// BITLSHIFT(number, shift_amount)
pub(crate) fn fn_bitlshift(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 2 {
return CalcResult::new_args_number_error(cell);
}
let number = match self.get_number(&args[0], cell) {
Ok(f) => f,
Err(s) => return s,
};
let shift = match self.get_number(&args[1], cell) {
Ok(f) => f,
Err(s) => return s,
};
if number.trunc() != number {
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
}
if number < 0.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be positive or zero".to_string(),
);
}
if number > MAX {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be less than 2^48-1".to_string(),
);
}
if shift.abs() > 53.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"shift amount must be less than 53".to_string(),
);
}
let number = number.trunc() as i64;
let shift = shift.trunc() as i64;
let result = if shift > 0 {
number << shift
} else {
number >> -shift
};
let result = result as f64;
if result.abs() > MAX {
return CalcResult::new_error(Error::NUM, cell, "BITLSHIFT overflow".to_string());
}
CalcResult::Number(result)
}
// BITRSHIFT(number, shift_amount)
pub(crate) fn fn_bitrshift(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 2 {
return CalcResult::new_args_number_error(cell);
}
let number = match self.get_number(&args[0], cell) {
Ok(f) => f,
Err(s) => return s,
};
let shift = match self.get_number(&args[1], cell) {
Ok(f) => f,
Err(s) => return s,
};
if number.trunc() != number {
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
}
if number < 0.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be positive or zero".to_string(),
);
}
if number > MAX {
return CalcResult::new_error(
Error::NUM,
cell,
"numbers must be less than 2^48-1".to_string(),
);
}
if shift.abs() > 53.0 {
return CalcResult::new_error(
Error::NUM,
cell,
"shift amount must be less than 53".to_string(),
);
}
let number = number.trunc() as i64;
let shift = shift.trunc() as i64;
let result = if shift > 0 {
number >> shift
} else {
number << -shift
};
let result = result as f64;
if result.abs() > MAX {
return CalcResult::new_error(Error::NUM, cell, "BITRSHIFT overflow".to_string());
}
CalcResult::Number(result)
}
}