Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,256 @@
|
||||
// 标准库入口来自实际 Dever 源码;参照只使用 dec,不调用 Dever 运行库。
|
||||
use dec::{Context, Decimal128};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
static NATIVE_CONTEXT: LazyLock<Context<Decimal128>> = LazyLock::new(Context::default);
|
||||
|
||||
struct DecimalInput {
|
||||
text: String,
|
||||
value: Decimal,
|
||||
native: Decimal128,
|
||||
places: i64,
|
||||
}
|
||||
|
||||
fn native_parse(text: &str) -> Option<Decimal128> {
|
||||
let mut context = NATIVE_CONTEXT.clone();
|
||||
let value = context.parse(text).ok()?;
|
||||
(value.is_finite() && !context.status().inexact()).then_some(value)
|
||||
}
|
||||
|
||||
fn parsed<const NATIVE: bool>(values: &[String]) -> Result<Vec<Option<[u8; 16]>>, Fault> {
|
||||
values
|
||||
.iter()
|
||||
.map(|text| {
|
||||
Ok(if NATIVE {
|
||||
native_parse(text).map(|value| value.to_be_bytes())
|
||||
} else {
|
||||
DECIMAL_PARSE(text)?.map(Decimal::to_be_bytes)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct NativeDisplay(Decimal128);
|
||||
impl std::fmt::Display for NativeDisplay {
|
||||
fn fmt(&self, output: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let value = Context::<Decimal128>::default().reduce(self.0);
|
||||
if value.is_zero() {
|
||||
output.write_str("0")
|
||||
} else {
|
||||
write!(output, "{value}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn formatted<const NATIVE: bool>(values: &[DecimalInput]) -> Result<Vec<String>, Fault> {
|
||||
values
|
||||
.iter()
|
||||
.map(|input| {
|
||||
if NATIVE {
|
||||
Ok(NativeDisplay(input.native).to_string())
|
||||
} else {
|
||||
DECIMAL_TEXT(input.value)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn native_round(value: Decimal128, places: i64) -> Option<Decimal128> {
|
||||
let exponent = i32::try_from(places.checked_neg()?).ok()?;
|
||||
if !(-6176..=6111).contains(&exponent) {
|
||||
return None;
|
||||
}
|
||||
let mut context = NATIVE_CONTEXT.clone();
|
||||
let mut quantum = Decimal128::ONE;
|
||||
context.set_exponent(&mut quantum, exponent);
|
||||
let value = context.quantize(value, quantum);
|
||||
(value.is_finite() && !context.status().underflow() && !context.status().invalid_context())
|
||||
.then_some(value)
|
||||
}
|
||||
|
||||
fn rounded<const NATIVE: bool>(values: &[DecimalInput]) -> Result<Vec<Option<[u8; 16]>>, Fault> {
|
||||
Ok(values
|
||||
.iter()
|
||||
.map(|input| {
|
||||
if NATIVE {
|
||||
native_round(input.native, input.places).map(|value| value.to_be_bytes())
|
||||
} else {
|
||||
DECIMAL_ROUND(input.value, input.places)
|
||||
.ok()
|
||||
.map(Decimal::to_be_bytes)
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn negated<const NATIVE: bool>(values: &[DecimalInput]) -> Result<Vec<[u8; 16]>, Fault> {
|
||||
Ok(values
|
||||
.iter()
|
||||
.map(|input| {
|
||||
if NATIVE {
|
||||
(-input.native).to_be_bytes()
|
||||
} else {
|
||||
(-input.value).to_be_bytes()
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn compared<const NATIVE: bool>(
|
||||
values: &[DecimalInput],
|
||||
) -> Result<Vec<(bool, Option<std::cmp::Ordering>)>, Fault> {
|
||||
Ok(values
|
||||
.windows(2)
|
||||
.map(|pair| {
|
||||
if NATIVE {
|
||||
(
|
||||
pair[0].native == pair[1].native,
|
||||
pair[0].native.partial_cmp(&pair[1].native),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
pair[0].value == pair[1].value,
|
||||
pair[0].value.partial_cmp(&pair[1].value),
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn byte_score(values: &[Option<[u8; 16]>]) -> u64 {
|
||||
values
|
||||
.iter()
|
||||
.flatten()
|
||||
.flat_map(|value| value.iter())
|
||||
.map(|value| u64::from(*value))
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn text_score(values: &[String]) -> u64 {
|
||||
values
|
||||
.iter()
|
||||
.flat_map(|value| value.bytes())
|
||||
.map(u64::from)
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("case,sample,implementation,nanoseconds,checksum");
|
||||
let spellings = [
|
||||
"0",
|
||||
"-0",
|
||||
"1.2300",
|
||||
"-12.345",
|
||||
"1E-6176",
|
||||
"1E6111",
|
||||
"9.999999999999999999999999999999999E6144",
|
||||
"1234567890123456789012345678901234",
|
||||
"1.25",
|
||||
"1.35",
|
||||
"-250",
|
||||
"+.125",
|
||||
"1e-34",
|
||||
"1.000000000000000000000000000000000",
|
||||
];
|
||||
let texts = spellings
|
||||
.iter()
|
||||
.cycle()
|
||||
.take(112)
|
||||
.map(|text| (*text).to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
let inputs = texts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, text)| DecimalInput {
|
||||
text: text.clone(),
|
||||
value: Decimal::parse(text).unwrap(),
|
||||
native: native_parse(text).unwrap(),
|
||||
places: [0, 1, 2, -2, 6176, -6111][index % 6],
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
compare(
|
||||
"decimal_parse_valid",
|
||||
&texts,
|
||||
1000,
|
||||
parsed::<false>,
|
||||
parsed::<true>,
|
||||
|value| byte_score(value),
|
||||
);
|
||||
let invalid = [
|
||||
"",
|
||||
"+",
|
||||
"NaN",
|
||||
"-sNaN",
|
||||
"Infinity",
|
||||
"nan123",
|
||||
" 1",
|
||||
"1 ",
|
||||
"1_000",
|
||||
"1e",
|
||||
"1\0",
|
||||
"雪",
|
||||
"1e9999",
|
||||
"1e-9999",
|
||||
"12345678901234567890123456789012345",
|
||||
]
|
||||
.iter()
|
||||
.cycle()
|
||||
.take(120)
|
||||
.map(|value| (*value).to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
assert!(
|
||||
parsed::<false>(&invalid)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.all(Option::is_none)
|
||||
);
|
||||
compare(
|
||||
"decimal_parse_invalid",
|
||||
&invalid,
|
||||
1000,
|
||||
parsed::<false>,
|
||||
parsed::<true>,
|
||||
|value| byte_score(value),
|
||||
);
|
||||
compare(
|
||||
"decimal_format",
|
||||
&inputs,
|
||||
1000,
|
||||
formatted::<false>,
|
||||
formatted::<true>,
|
||||
|value| text_score(value),
|
||||
);
|
||||
compare(
|
||||
"decimal_round",
|
||||
&inputs,
|
||||
1000,
|
||||
rounded::<false>,
|
||||
rounded::<true>,
|
||||
|value| byte_score(value),
|
||||
);
|
||||
compare(
|
||||
"decimal_negate",
|
||||
&inputs,
|
||||
1000,
|
||||
negated::<false>,
|
||||
negated::<true>,
|
||||
|value| value.iter().flatten().map(|value| u64::from(*value)).sum(),
|
||||
);
|
||||
compare(
|
||||
"decimal_compare",
|
||||
&inputs,
|
||||
1000,
|
||||
compared::<false>,
|
||||
compared::<true>,
|
||||
|value| {
|
||||
value
|
||||
.iter()
|
||||
.map(|(equal, order)| {
|
||||
u64::from(*equal) + u64::from(order == &Some(std::cmp::Ordering::Less))
|
||||
})
|
||||
.sum()
|
||||
},
|
||||
);
|
||||
wire_cases(&inputs);
|
||||
storage_cases();
|
||||
}
|
||||
Reference in new issue
Block a user