Skip to content

Commit

Permalink
Merge pull request #351 from paupino/version/1.12
Browse files Browse the repository at this point in the history
Version 1.12 with some internal housekeeping
  • Loading branch information
paupino committed Apr 23, 2021
2 parents 9c2a116 + 8731619 commit d51e809
Show file tree
Hide file tree
Showing 20 changed files with 1,027 additions and 1,004 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT"
name = "rust_decimal"
readme = "./README.md"
repository = "https://github.com/paupino/rust-decimal"
version = "1.11.1"
version = "1.12.0"
exclude = [ "tests/generated/*" ]

[dependencies]
Expand Down
28 changes: 28 additions & 0 deletions VERSION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Version History

## 1.12.0

This version releases faster operation support for `add`, `sub`, `cmp`, `rem` and `mul` to match the renewed `div` strategy.
It does this by leveraging 64 bit support when it makes sense, while attempting to still keep 32 bit optimizations in place.
To ensure correct functionality, thousands more tests were included to cover a wide variety of different scenarios
and bit combinations. Compared to previous operations, we get the following speed improvements:
* `add` - up to 2.2x faster
* `div` - up to 428x faster
* `mul` - up to 1.8x faster
* `rem` - up to 1.08x faster
* `sub` - up to 2.5x faster

Of course, if old functionality is desired, it can be re-enabled by using the `legacy-ops` feature.

Other improvements include:
* Remove unnecessary `String` allocation when parsing a scientific number format. Thanks [@thomcc](https://github.com/thomcc) for the fix [#350](https://github.com/paupino/rust-decimal/pull/350).
* Fixes overflow bug with `sqrt` when using the smallest possible representable number. [#349](https://github.com/paupino/rust-decimal/pull/349).
* Some minor optimizations in the `maths` feature. Future work will involve speeding up this feature by keeping operations
in an internal format until required.
* Added associated constants for `MIN`, `MAX` and `ZERO`. Deprecated `min_value()` and `max_value()` in favor of these new
constants.
* `-0` now gets corrected to `0`. During operation rewrite I needed to consider operations such as `-0 * 2` - in cases like
this I opted towards `0` always being the right number and `-0` being superfluous (since `+0 == -0`). Consequently, parsing
`-0` etc _in general_ will automatically be parsed as `0`. Of course, this _may_ be a breaking change so if this
functionality is required then please create an issue with the use case described.
* Small breaking change by renaming `is_negative` to `negative` in `UnpackedDecimal`.
* Some internal housekeeping was made to help make way for version 2.0 improvements.

## 1.11.1

This is a documentation only release and has no new functionality included. Thank you [@c410-f3r](https://github.com/c410-f3r) for the documentation fix.
Expand Down
4 changes: 2 additions & 2 deletions benches/lib_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ bench_decimal_op!(div_negative_point_five, /, "2.01", "-0.5");
bench_decimal_op!(div_pi, /, "2.01", "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "2.01", "-3.1415926535897932384626433832");
bench_decimal_op!(div_no_underflow, /, "1.02343545345", "0.35454343453");
bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);
bench_fold_op!(rem_10k, %, Decimal::max_value(), 10_000);
bench_fold_op!(div_10k, /, Decimal::MAX, 10_000);
bench_fold_op!(rem_10k, %, Decimal::MAX, 10_000);

/* Iteration */
struct DecimalIterator {
Expand Down
2 changes: 1 addition & 1 deletion macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rust_decimal_macros"
version = "1.11.1"
version = "1.12.0"
authors = ["Paul Mason <paul@form1.co.nz>"]
edition = "2018"
description = "Shorthand macros to assist creating Decimal types."
Expand Down
42 changes: 42 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Sign mask for the flags field. A value of zero in this bit indicates a
// positive Decimal value, and a value of one in this bit indicates a
// negative Decimal value.
pub const SIGN_MASK: u32 = 0x8000_0000;
pub const UNSIGN_MASK: u32 = 0x4FFF_FFFF;

// Scale mask for the flags field. This byte in the flags field contains
// the power of 10 to divide the Decimal value by. The scale byte must
// contain a value between 0 and 28 inclusive.
pub const SCALE_MASK: u32 = 0x00FF_0000;
pub const U8_MASK: u32 = 0x0000_00FF;
pub const U32_MASK: u64 = 0xFFFF_FFFF;

// Number of bits scale is shifted by.
pub const SCALE_SHIFT: u32 = 16;
// Number of bits sign is shifted by.
pub const SIGN_SHIFT: u32 = 31;

// The maximum string buffer size used for serialization purposes. 31 is optimal, however we align
// to the byte boundary for simplicity.
pub const MAX_STR_BUFFER_SIZE: usize = 32;

// The maximum supported precision
pub const MAX_PRECISION: u32 = 28;
#[cfg(not(feature = "legacy-ops"))]
pub const MAX_PRECISION_I32: i32 = 28;
// 79,228,162,514,264,337,593,543,950,335
pub const MAX_I128_REPR: i128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;

// Fast access for 10^n where n is 0-9
pub const POWERS_10: [u32; 10] = [
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
];

#[cfg(not(feature = "legacy-ops"))]
// The maximum power of 10 that a 32 bit integer can store
pub const MAX_I32_SCALE: i32 = 9;
#[cfg(not(feature = "legacy-ops"))]
// The maximum power of 10 that a 64 bit integer can store
pub const MAX_I64_SCALE: u32 = 19;
#[cfg(not(feature = "legacy-ops"))]
pub const U32_MAX: u64 = u32::MAX as u64;
36 changes: 10 additions & 26 deletions src/postgres.rs → src/db.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::constants::MAX_PRECISION;
use crate::{
decimal::{div_by_u32, is_all_zero, mul_by_u32, MAX_PRECISION},
ops::array::{div_by_u32, is_all_zero, mul_by_u32},
Decimal,
};
use core::{convert::TryInto, fmt, result::*};
use core::{convert::TryInto, fmt};
use std::error;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -37,7 +38,7 @@ impl Decimal {
digits,
weight,
}: PostgresDecimal<D>,
) -> Result<Self, InvalidDecimal> {
) -> Self {
let mut digits = digits.into_iter().collect::<Vec<_>>();

let fractionals_part_count = digits.len() as i32 + (-weight as i32) - 1;
Expand Down Expand Up @@ -69,8 +70,7 @@ impl Decimal {
} else if fract_pow == MAX_PRECISION + 4 {
// rounding last digit
if digit >= 5000 {
result +=
Decimal::new(1 as i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
result += Decimal::new(1_i64, 0) / Decimal::from_i128_with_scale(10i128.pow(MAX_PRECISION), 0);
}
}
}
Expand All @@ -79,8 +79,7 @@ impl Decimal {
result.set_sign_negative(neg);
// Rescale to the postgres value, automatically rounding as needed.
result.rescale(scale as u32);

Ok(result)
result
}

fn to_postgres(self) -> PostgresDecimal<Vec<i16>> {
Expand Down Expand Up @@ -176,8 +175,7 @@ mod diesel {
weight,
scale,
digits: digits.iter().copied().map(|v| v.try_into().unwrap()),
})
.map_err(Box::new)?)
}))
}
}

Expand All @@ -190,11 +188,6 @@ mod diesel {
}

impl<'a> From<&'a Decimal> for PgNumeric {
// NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
// with `.take_while(Zero::is_zero)`, but that's a false positive.
// The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
// is called. There is no impl for `&i16` that would work with this closure.
#[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
fn from(decimal: &'a Decimal) -> Self {
let PostgresDecimal {
neg,
Expand All @@ -203,8 +196,6 @@ mod diesel {
digits,
} = decimal.to_postgres();

let digits = digits.into_iter().map(|v| v.try_into().unwrap()).collect();

if neg {
PgNumeric::Negative { digits, scale, weight }
} else {
Expand Down Expand Up @@ -551,15 +542,11 @@ mod postgres {
weight,
scale,
digits: groups.into_iter(),
})
.map_err(Box::new)?)
}))
}

fn accepts(ty: &Type) -> bool {
match ty {
&Type::NUMERIC => true,
_ => false,
}
matches!(*ty, Type::NUMERIC)
}
}

Expand Down Expand Up @@ -598,10 +585,7 @@ mod postgres {
}

fn accepts(ty: &Type) -> bool {
match ty {
&Type::NUMERIC => true,
_ => false,
}
matches!(*ty, Type::NUMERIC)
}

to_sql_checked!();
Expand Down

0 comments on commit d51e809

Please sign in to comment.