/*! 🧮 MathBox - 数学計算Box * * ## 📝 概要 * 高度な数学演算を提供するBox。Python mathモジュールや * JavaScript Math オブジェクトと同様の機能を提供。 * * ## 🛠️ 利用可能メソッド * * ### 🔢 基本計算 * - `abs(value)` - 絶対値 * - `max(a, b)` - 最大値 * - `min(a, b)` - 最小値 * - `pow(base, exp)` - 累乗 (base^exp) * - `sqrt(value)` - 平方根 * * ### 📐 三角関数 * - `sin(radians)` - 正弦 * - `cos(radians)` - 余弦 * - `tan(radians)` - 正接 * * ### 📊 対数・指数関数 * - `log(value)` - 自然対数 (ln) * - `log10(value)` - 常用対数 * - `exp(value)` - 指数関数 (e^x) * * ### 🔄 丸め関数 * - `floor(value)` - 切り下げ * - `ceil(value)` - 切り上げ * - `round(value)` - 四捨五入 * * ### 📏 定数取得 * - `getPi()` - 円周率π (3.14159...) * - `getE()` - 自然対数の底e (2.71828...) * * ## 💡 使用例 * ```nyash * local math, result * math = new MathBox() * * result = math.abs(-42) // 42 * result = math.max(10, 25) // 25 * result = math.sqrt(16) // 4.0 * result = math.pow(2, 3) // 8.0 * result = math.sin(math.getPi() / 2) // 1.0 * * // 計算例 * local pi, area * pi = math.getPi() * area = pi * math.pow(5, 2) // 半径5の円の面積 * ``` * * ## ⚠️ 注意 * - 三角関数の引数はラジアン * - 負数の平方根・対数はエラー * - オーバーフロー時は標準f64の動作に従う * - 整数演算は自動でFloatBoxに変換される場合あり */ use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, BoxCore, BoxBase, next_box_id}; use std::fmt::{Debug, Display}; use std::any::Any; /// 数学演算を提供するBox #[derive(Debug, Clone)] pub struct MathBox { base: BoxBase, } impl MathBox { pub fn new() -> Self { Self { base: BoxBase::new() } } /// 絶対値を計算 pub fn abs(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(int_box.value.abs())) } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new(float_box.value.abs())) } else { Box::new(StringBox::new("Error: abs() requires numeric input")) } } /// 最大値を返す pub fn max(&self, a: Box, b: Box) -> Box { if let (Some(a_int), Some(b_int)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { Box::new(IntegerBox::new(a_int.value.max(b_int.value))) } else if let (Some(a_float), Some(b_float)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { Box::new(FloatBox::new(a_float.value.max(b_float.value))) } else { Box::new(StringBox::new("Error: max() requires numeric inputs")) } } /// 最小値を返す pub fn min(&self, a: Box, b: Box) -> Box { if let (Some(a_int), Some(b_int)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { Box::new(IntegerBox::new(a_int.value.min(b_int.value))) } else if let (Some(a_float), Some(b_float)) = ( a.as_any().downcast_ref::(), b.as_any().downcast_ref::() ) { Box::new(FloatBox::new(a_float.value.min(b_float.value))) } else { Box::new(StringBox::new("Error: min() requires numeric inputs")) } } /// 累乗を計算 pub fn pow(&self, base: Box, exp: Box) -> Box { if let (Some(base_int), Some(exp_int)) = ( base.as_any().downcast_ref::(), exp.as_any().downcast_ref::() ) { if exp_int.value >= 0 { let result = (base_int.value as f64).powi(exp_int.value as i32); Box::new(FloatBox::new(result)) } else { Box::new(StringBox::new("Error: negative exponent")) } } else { Box::new(StringBox::new("Error: pow() requires numeric inputs")) } } /// 平方根を計算 pub fn sqrt(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { if int_box.value >= 0 { Box::new(FloatBox::new((int_box.value as f64).sqrt())) } else { Box::new(StringBox::new("Error: sqrt() of negative number")) } } else if let Some(float_box) = value.as_any().downcast_ref::() { if float_box.value >= 0.0 { Box::new(FloatBox::new(float_box.value.sqrt())) } else { Box::new(StringBox::new("Error: sqrt() of negative number")) } } else { Box::new(StringBox::new("Error: sqrt() requires numeric input")) } } /// 円周率πを返す #[allow(non_snake_case)] pub fn getPi(&self) -> Box { Box::new(FloatBox::new(std::f64::consts::PI)) } /// 自然対数の底eを返す #[allow(non_snake_case)] pub fn getE(&self) -> Box { Box::new(FloatBox::new(std::f64::consts::E)) } /// サイン(正弦) pub fn sin(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new((int_box.value as f64).sin())) } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new(float_box.value.sin())) } else { Box::new(StringBox::new("Error: sin() requires numeric input")) } } /// コサイン(余弦) pub fn cos(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new((int_box.value as f64).cos())) } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new(float_box.value.cos())) } else { Box::new(StringBox::new("Error: cos() requires numeric input")) } } /// タンジェント(正接) pub fn tan(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new((int_box.value as f64).tan())) } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new(float_box.value.tan())) } else { Box::new(StringBox::new("Error: tan() requires numeric input")) } } /// 自然対数 pub fn log(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { if int_box.value > 0 { Box::new(FloatBox::new((int_box.value as f64).ln())) } else { Box::new(StringBox::new("Error: log() of non-positive number")) } } else if let Some(float_box) = value.as_any().downcast_ref::() { if float_box.value > 0.0 { Box::new(FloatBox::new(float_box.value.ln())) } else { Box::new(StringBox::new("Error: log() of non-positive number")) } } else { Box::new(StringBox::new("Error: log() requires numeric input")) } } /// 常用対数(底10) pub fn log10(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { if int_box.value > 0 { Box::new(FloatBox::new((int_box.value as f64).log10())) } else { Box::new(StringBox::new("Error: log10() of non-positive number")) } } else if let Some(float_box) = value.as_any().downcast_ref::() { if float_box.value > 0.0 { Box::new(FloatBox::new(float_box.value.log10())) } else { Box::new(StringBox::new("Error: log10() of non-positive number")) } } else { Box::new(StringBox::new("Error: log10() requires numeric input")) } } /// 指数関数(e^x) pub fn exp(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new((int_box.value as f64).exp())) } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(FloatBox::new(float_box.value.exp())) } else { Box::new(StringBox::new("Error: exp() requires numeric input")) } } /// 床関数(切り下げ) pub fn floor(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(int_box.value)) // 整数はそのまま } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(float_box.value.floor() as i64)) } else { Box::new(StringBox::new("Error: floor() requires numeric input")) } } /// 天井関数(切り上げ) pub fn ceil(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(int_box.value)) // 整数はそのまま } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(float_box.value.ceil() as i64)) } else { Box::new(StringBox::new("Error: ceil() requires numeric input")) } } /// 四捨五入 pub fn round(&self, value: Box) -> Box { if let Some(int_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(int_box.value)) // 整数はそのまま } else if let Some(float_box) = value.as_any().downcast_ref::() { Box::new(IntegerBox::new(float_box.value.round() as i64)) } else { Box::new(StringBox::new("Error: round() requires numeric input")) } } } impl BoxCore for MathBox { fn box_id(&self) -> u64 { self.base.id } fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "MathBox()") } } impl NyashBox for MathBox { fn type_name(&self) -> &'static str { "MathBox" } fn to_string_box(&self) -> StringBox { StringBox::new("MathBox()") } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_math) = other.as_any().downcast_ref::() { BoolBox::new(self.box_id() == other_math.box_id()) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } } impl Display for MathBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } } /// 浮動小数点数Box #[derive(Debug, Clone)] pub struct FloatBox { pub value: f64, base: BoxBase, } impl FloatBox { pub fn new(value: f64) -> Self { Self { value, base: BoxBase::new() } } } impl BoxCore for FloatBox { fn box_id(&self) -> u64 { self.base.id } fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.value) } } impl NyashBox for FloatBox { fn type_name(&self) -> &'static str { "FloatBox" } fn to_string_box(&self) -> StringBox { StringBox::new(&self.value.to_string()) } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_float) = other.as_any().downcast_ref::() { BoolBox::new((self.value - other_float.value).abs() < f64::EPSILON) } else if let Some(other_int) = other.as_any().downcast_ref::() { BoolBox::new((self.value - other_int.value as f64).abs() < f64::EPSILON) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } } impl Display for FloatBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } } /// 範囲を表すBox #[derive(Debug, Clone)] pub struct RangeBox { pub start: i64, pub end: i64, pub step: i64, base: BoxBase, } impl RangeBox { pub fn new(start: i64, end: i64, step: i64) -> Self { Self { start, end, step, base: BoxBase::new() } } /// イテレータとして値を生成 pub fn iter(&self) -> Vec { let mut result = Vec::new(); let mut current = self.start; if self.step > 0 { while current < self.end { result.push(current); current += self.step; } } else if self.step < 0 { while current > self.end { result.push(current); current += self.step; } } result } } impl BoxCore for RangeBox { fn box_id(&self) -> u64 { self.base.id } fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Range({}, {}, {})", self.start, self.end, self.step) } } impl NyashBox for RangeBox { fn type_name(&self) -> &'static str { "RangeBox" } fn to_string_box(&self) -> StringBox { StringBox::new(&format!("Range({}, {}, {})", self.start, self.end, self.step)) } fn clone_box(&self) -> Box { Box::new(self.clone()) } fn equals(&self, other: &dyn NyashBox) -> BoolBox { if let Some(other_range) = other.as_any().downcast_ref::() { BoolBox::new( self.start == other_range.start && self.end == other_range.end && self.step == other_range.step ) } else { BoolBox::new(false) } } fn as_any(&self) -> &dyn Any { self } } impl Display for RangeBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } }