unitforge 0.3.16__tar.gz → 0.3.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unitforge-0.3.16 → unitforge-0.3.18}/Cargo.lock +1 -1
- {unitforge-0.3.16 → unitforge-0.3.18}/Cargo.toml +1 -1
- {unitforge-0.3.16 → unitforge-0.3.18}/PKG-INFO +1 -3
- {unitforge-0.3.16 → unitforge-0.3.18}/src/impl_macros.rs +48 -27
- unitforge-0.3.18/src/internal.rs +16 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/lib.rs +3 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/prelude.rs +5 -1
- unitforge-0.3.18/src/quantities/inverse_angle.rs +26 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/inverse_distance.rs +0 -3
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/inverse_stress.rs +0 -1
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/stress.rs +0 -2
- {unitforge-0.3.16 → unitforge-0.3.18}/src/relations.rs +5 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/matrix3.rs +5 -13
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/matrix3.rs +12 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/quantities.rs +15 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/.gitignore +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/.gitlab-ci.yml +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/Readme.md +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/Readme_py.md +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/pyproject.toml +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/python/unitforge/__init__.py +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/scripts/generate_python_stubs.py +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/acceleration.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/angle.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/angular_acceleration.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/angular_velocity.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/area.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/area_of_moment.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/charge.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/compliance.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/density.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/distance.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_area.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_distance.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_div_distance_power_four.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_per_volume.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_stress.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/force_volume.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/inverse_area.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/mass.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/mass_div_time_squared_volume.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/mass_per_distance.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/rotational_stiffness.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/stiffness.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/strain.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/stress_squared.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/time.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/velocity.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/velocity_squared.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/voltage.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities/volume.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/quantities.template.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/bindings/matrix3_py.template.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/bindings/vector3_py.template.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/matrix2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/matrix2x3.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/matrix3x2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/vector2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/small_linalg/vector3.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/tests/quantity_unit_tests.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/src/tests/serde_tests.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/matrix2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/matrix2x3.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/matrix3x2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/ndarray_dot.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/small_linalg_interfaces.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/test_quantities.py +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/test_small_linalg.py +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/typecheck/mypy_smoke.py +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/vector2.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/tests/vector3.rs +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/unitforge_macros/Cargo.toml +0 -0
- {unitforge-0.3.16 → unitforge-0.3.18}/unitforge_macros/src/lib.rs +0 -0
|
@@ -4,7 +4,7 @@ crate-type = ["cdylib", "rlib"]
|
|
|
4
4
|
|
|
5
5
|
[package]
|
|
6
6
|
name = "unitforge"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.18"
|
|
8
8
|
edition = "2021"
|
|
9
9
|
authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
|
|
10
10
|
description = "A library for unit and quantity consistent computations in Rust"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unitforge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.18
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Rust
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -9,9 +9,7 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
9
9
|
Requires-Dist: numpy>=2.2.0
|
|
10
10
|
Summary: A library for unit and quantity consistent computations in Rust
|
|
11
11
|
Keywords: units,quantities,simulation,physics
|
|
12
|
-
Author: Dr.Q team <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
|
|
13
12
|
Author-email: "Dr.Q team" <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
|
|
14
|
-
License: MIT
|
|
15
13
|
Requires-Python: >=3.7
|
|
16
14
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
17
15
|
Project-URL: Repository, https://gitlab.com/henrikjstromberg/unitforge
|
|
@@ -44,6 +44,9 @@ macro_rules! impl_quantity {
|
|
|
44
44
|
|
|
45
45
|
impl PhysicsQuantity for $type {
|
|
46
46
|
fn as_f64(&self) -> f64 {
|
|
47
|
+
if self.multiplier.abs() < f64::EPSILON {
|
|
48
|
+
return 0.0;
|
|
49
|
+
}
|
|
47
50
|
self.multiplier * 10_f64.powi(self.power)
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -67,7 +70,7 @@ macro_rules! impl_quantity {
|
|
|
67
70
|
let (multiplier, power) = Self::split_value(value);
|
|
68
71
|
let r = $type {
|
|
69
72
|
multiplier: multiplier * unit_multiplier,
|
|
70
|
-
power: power
|
|
73
|
+
power: $crate::internal::saturating_power_add(power, unit_power),
|
|
71
74
|
};
|
|
72
75
|
r
|
|
73
76
|
}
|
|
@@ -89,6 +92,9 @@ macro_rules! impl_quantity {
|
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
fn get_value(&self) -> f64 {
|
|
95
|
+
if self.multiplier.abs() < f64::EPSILON {
|
|
96
|
+
return 0.0;
|
|
97
|
+
}
|
|
92
98
|
self.multiplier * 10_f64.powi(self.power)
|
|
93
99
|
}
|
|
94
100
|
|
|
@@ -105,8 +111,12 @@ macro_rules! impl_quantity {
|
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
fn to(&self, unit: Self::Unit) -> f64 {
|
|
114
|
+
if self.multiplier.abs() < f64::EPSILON {
|
|
115
|
+
return 0.0;
|
|
116
|
+
}
|
|
108
117
|
let (unit_multiplier, unit_power) = unit.base_per_x();
|
|
109
|
-
self.multiplier / unit_multiplier
|
|
118
|
+
self.multiplier / unit_multiplier
|
|
119
|
+
* $crate::internal::pow10_delta(self.power, unit_power)
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
fn abs(self) -> Self {
|
|
@@ -140,6 +150,9 @@ macro_rules! impl_quantity {
|
|
|
140
150
|
}
|
|
141
151
|
|
|
142
152
|
fn from_exponential(multiplier: f64, power: i32) -> Self {
|
|
153
|
+
if multiplier.abs() < f64::EPSILON {
|
|
154
|
+
return Self::zero();
|
|
155
|
+
}
|
|
143
156
|
Self { multiplier, power }
|
|
144
157
|
}
|
|
145
158
|
|
|
@@ -165,11 +178,14 @@ macro_rules! impl_quantity {
|
|
|
165
178
|
|
|
166
179
|
fn optimize(&mut self) {
|
|
167
180
|
if self.multiplier.abs() < f64::EPSILON {
|
|
181
|
+
self.multiplier = 0.0;
|
|
182
|
+
self.power = 0;
|
|
168
183
|
return;
|
|
169
184
|
}
|
|
170
185
|
let power_on_multiplier = self.multiplier.abs().log10().round() as i32;
|
|
171
186
|
self.multiplier /= 10_f64.powi(power_on_multiplier);
|
|
172
|
-
self.power
|
|
187
|
+
self.power =
|
|
188
|
+
$crate::internal::saturating_power_add(self.power, power_on_multiplier);
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
const INFINITY: Self = Self {
|
|
@@ -300,7 +316,7 @@ macro_rules! impl_quantity {
|
|
|
300
316
|
other,
|
|
301
317
|
&Self {
|
|
302
318
|
multiplier: self.multiplier,
|
|
303
|
-
power: self.power
|
|
319
|
+
power: $crate::internal::saturating_power_sub(self.power, 9),
|
|
304
320
|
},
|
|
305
321
|
)
|
|
306
322
|
}
|
|
@@ -334,8 +350,9 @@ macro_rules! impl_quantity {
|
|
|
334
350
|
|
|
335
351
|
fn add(self, other: Self) -> Self {
|
|
336
352
|
let common_power = self.power.max(other.power);
|
|
337
|
-
let multiplier = self.multiplier
|
|
338
|
-
|
|
353
|
+
let multiplier = self.multiplier
|
|
354
|
+
* $crate::internal::pow10_delta(self.power, common_power)
|
|
355
|
+
+ other.multiplier * $crate::internal::pow10_delta(other.power, common_power);
|
|
339
356
|
let mut res = Self {
|
|
340
357
|
multiplier,
|
|
341
358
|
power: common_power,
|
|
@@ -349,9 +366,10 @@ macro_rules! impl_quantity {
|
|
|
349
366
|
type Output = Self;
|
|
350
367
|
|
|
351
368
|
fn sub(self, other: Self) -> Self {
|
|
352
|
-
let common_power = (self.power
|
|
353
|
-
let multiplier = self.multiplier
|
|
354
|
-
|
|
369
|
+
let common_power = $crate::internal::average_power(self.power, other.power);
|
|
370
|
+
let multiplier = self.multiplier
|
|
371
|
+
* $crate::internal::pow10_delta(self.power, common_power)
|
|
372
|
+
- other.multiplier * $crate::internal::pow10_delta(other.power, common_power);
|
|
355
373
|
|
|
356
374
|
let mut res = Self {
|
|
357
375
|
multiplier,
|
|
@@ -369,7 +387,7 @@ macro_rules! impl_quantity {
|
|
|
369
387
|
let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
|
|
370
388
|
Self {
|
|
371
389
|
multiplier: self.multiplier / rhs_multiplier,
|
|
372
|
-
power: self.power
|
|
390
|
+
power: $crate::internal::saturating_power_sub(self.power, rhs_power),
|
|
373
391
|
}
|
|
374
392
|
}
|
|
375
393
|
}
|
|
@@ -381,7 +399,7 @@ macro_rules! impl_quantity {
|
|
|
381
399
|
let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
|
|
382
400
|
Self {
|
|
383
401
|
multiplier: self.multiplier * rhs_multiplier,
|
|
384
|
-
power: self.power
|
|
402
|
+
power: $crate::internal::saturating_power_add(self.power, rhs_power),
|
|
385
403
|
}
|
|
386
404
|
}
|
|
387
405
|
}
|
|
@@ -396,9 +414,10 @@ macro_rules! impl_quantity {
|
|
|
396
414
|
|
|
397
415
|
impl AddAssign for $type {
|
|
398
416
|
fn add_assign(&mut self, other: Self) {
|
|
399
|
-
let common_power = (self.power
|
|
400
|
-
self.multiplier = self.multiplier
|
|
401
|
-
|
|
417
|
+
let common_power = $crate::internal::average_power(self.power, other.power);
|
|
418
|
+
self.multiplier = self.multiplier
|
|
419
|
+
* $crate::internal::pow10_delta(self.power, common_power)
|
|
420
|
+
+ other.multiplier * $crate::internal::pow10_delta(other.power, common_power);
|
|
402
421
|
self.power = common_power;
|
|
403
422
|
self.optimize();
|
|
404
423
|
}
|
|
@@ -406,9 +425,10 @@ macro_rules! impl_quantity {
|
|
|
406
425
|
|
|
407
426
|
impl SubAssign for $type {
|
|
408
427
|
fn sub_assign(&mut self, other: Self) {
|
|
409
|
-
let common_power = (self.power
|
|
410
|
-
self.multiplier = self.multiplier
|
|
411
|
-
|
|
428
|
+
let common_power = $crate::internal::average_power(self.power, other.power);
|
|
429
|
+
self.multiplier = self.multiplier
|
|
430
|
+
* $crate::internal::pow10_delta(self.power, common_power)
|
|
431
|
+
- other.multiplier * $crate::internal::pow10_delta(other.power, common_power);
|
|
412
432
|
self.power = common_power;
|
|
413
433
|
self.optimize();
|
|
414
434
|
}
|
|
@@ -418,7 +438,7 @@ macro_rules! impl_quantity {
|
|
|
418
438
|
fn mul_assign(&mut self, rhs: f64) {
|
|
419
439
|
let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
|
|
420
440
|
self.multiplier *= rhs_multiplier;
|
|
421
|
-
self.power
|
|
441
|
+
self.power = $crate::internal::saturating_power_add(self.power, rhs_power);
|
|
422
442
|
}
|
|
423
443
|
}
|
|
424
444
|
|
|
@@ -426,7 +446,7 @@ macro_rules! impl_quantity {
|
|
|
426
446
|
fn div_assign(&mut self, rhs: f64) {
|
|
427
447
|
let (rhs_multiplier, rhs_power) = Self::split_value(rhs);
|
|
428
448
|
self.multiplier /= rhs_multiplier;
|
|
429
|
-
self.power
|
|
449
|
+
self.power = $crate::internal::saturating_power_sub(self.power, rhs_power);
|
|
430
450
|
}
|
|
431
451
|
}
|
|
432
452
|
|
|
@@ -594,10 +614,10 @@ macro_rules! impl_quantity {
|
|
|
594
614
|
|
|
595
615
|
impl $type {
|
|
596
616
|
pub fn optimal_unit(&self, choices: HashSet<$unit>) -> Option<$unit> {
|
|
597
|
-
let mut min_value =
|
|
617
|
+
let mut min_value = i64::MAX;
|
|
598
618
|
let mut best_unit = None;
|
|
599
619
|
for unit in choices {
|
|
600
|
-
let difference = (self.power - unit.base_per_x().1).abs();
|
|
620
|
+
let difference = (i64::from(self.power) - i64::from(unit.base_per_x().1)).abs();
|
|
601
621
|
if difference < min_value {
|
|
602
622
|
min_value = difference;
|
|
603
623
|
best_unit = Some(unit);
|
|
@@ -650,7 +670,8 @@ macro_rules! impl_div_with_self_to_f64 {
|
|
|
650
670
|
type Output = f64;
|
|
651
671
|
|
|
652
672
|
fn div(self, rhs: Self) -> Self::Output {
|
|
653
|
-
(self.multiplier / rhs.multiplier)
|
|
673
|
+
(self.multiplier / rhs.multiplier)
|
|
674
|
+
* $crate::internal::pow10_delta(self.power, rhs.power)
|
|
654
675
|
}
|
|
655
676
|
}
|
|
656
677
|
};
|
|
@@ -665,7 +686,7 @@ macro_rules! impl_mul {
|
|
|
665
686
|
fn mul(self, rhs: $rhs) -> Self::Output {
|
|
666
687
|
<$result>::from_exponential(
|
|
667
688
|
self.multiplier * rhs.multiplier,
|
|
668
|
-
self.power
|
|
689
|
+
$crate::internal::saturating_power_add(self.power, rhs.power),
|
|
669
690
|
)
|
|
670
691
|
}
|
|
671
692
|
}
|
|
@@ -676,7 +697,7 @@ macro_rules! impl_mul {
|
|
|
676
697
|
fn mul(self, rhs: $lhs) -> Self::Output {
|
|
677
698
|
<$result>::from_exponential(
|
|
678
699
|
self.multiplier * rhs.multiplier,
|
|
679
|
-
self.power
|
|
700
|
+
$crate::internal::saturating_power_add(self.power, rhs.power),
|
|
680
701
|
)
|
|
681
702
|
}
|
|
682
703
|
}
|
|
@@ -774,7 +795,7 @@ macro_rules! impl_mul_with_self {
|
|
|
774
795
|
fn mul(self, rhs: $lhs) -> Self::Output {
|
|
775
796
|
<$result>::from_exponential(
|
|
776
797
|
self.multiplier * rhs.multiplier,
|
|
777
|
-
self.power
|
|
798
|
+
$crate::internal::saturating_power_add(self.power, rhs.power),
|
|
778
799
|
)
|
|
779
800
|
}
|
|
780
801
|
}
|
|
@@ -831,7 +852,7 @@ macro_rules! impl_div {
|
|
|
831
852
|
fn div(self, rhs: $rhs) -> Self::Output {
|
|
832
853
|
<$result>::from_exponential(
|
|
833
854
|
self.multiplier / rhs.multiplier,
|
|
834
|
-
self.power
|
|
855
|
+
$crate::internal::saturating_power_sub(self.power, rhs.power),
|
|
835
856
|
)
|
|
836
857
|
}
|
|
837
858
|
}
|
|
@@ -889,7 +910,7 @@ macro_rules! impl_sqrt {
|
|
|
889
910
|
} else {
|
|
890
911
|
<$res>::from_exponential(
|
|
891
912
|
self.multiplier.sqrt() * 10_f64.sqrt(),
|
|
892
|
-
(self.power
|
|
913
|
+
$crate::internal::saturating_power_sub(self.power, 1) / 2,
|
|
893
914
|
)
|
|
894
915
|
}
|
|
895
916
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
pub fn saturating_power_add(lhs: i32, rhs: i32) -> i32 {
|
|
2
|
+
lhs.saturating_add(rhs)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
pub fn saturating_power_sub(lhs: i32, rhs: i32) -> i32 {
|
|
6
|
+
lhs.saturating_sub(rhs)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
pub fn average_power(lhs: i32, rhs: i32) -> i32 {
|
|
10
|
+
let average = (i64::from(lhs) + i64::from(rhs)) / 2;
|
|
11
|
+
average.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pub fn pow10_delta(lhs: i32, rhs: i32) -> f64 {
|
|
15
|
+
10_f64.powi(saturating_power_sub(lhs, rhs))
|
|
16
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pub mod impl_macros;
|
|
3
3
|
pub use impl_macros::*;
|
|
4
4
|
|
|
5
|
+
mod internal;
|
|
5
6
|
pub mod prelude;
|
|
6
7
|
mod relations;
|
|
7
8
|
|
|
@@ -82,6 +83,8 @@ pub mod quantities {
|
|
|
82
83
|
pub use volume::*;
|
|
83
84
|
pub mod voltage;
|
|
84
85
|
pub use voltage::*;
|
|
86
|
+
pub mod inverse_angle;
|
|
87
|
+
pub use inverse_angle::*;
|
|
85
88
|
}
|
|
86
89
|
pub use quantities::*;
|
|
87
90
|
|
|
@@ -252,7 +252,11 @@ impl PhysicsQuantity for f64 {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
fn from_exponential(multiplier: f64, power: i32) -> Self {
|
|
255
|
-
multiplier
|
|
255
|
+
if multiplier.abs() < f64::EPSILON {
|
|
256
|
+
0.0
|
|
257
|
+
} else {
|
|
258
|
+
multiplier * 10_f64.powi(power)
|
|
259
|
+
}
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
fn min(self, other: Self) -> Self {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
use crate::impl_macros::macros::*;
|
|
2
|
+
|
|
3
|
+
#[cfg_attr(feature = "strum", derive(EnumIter))]
|
|
4
|
+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
5
|
+
#[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
|
|
6
|
+
#[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
|
|
7
|
+
pub enum InverseAngleUnit {
|
|
8
|
+
_rad,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
impl PhysicsUnit for InverseAngleUnit {
|
|
12
|
+
fn name(&self) -> &str {
|
|
13
|
+
match &self {
|
|
14
|
+
InverseAngleUnit::_rad => "1/rad",
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn base_per_x(&self) -> (f64, i32) {
|
|
19
|
+
match self {
|
|
20
|
+
InverseAngleUnit::_rad => (1., 0),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl_quantity!(InverseAngle, InverseAngleUnit, [InverseAngleUnit::_rad]);
|
|
26
|
+
impl_div_with_self_to_f64!(InverseAngle);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
use crate::impl_macros::macros::*;
|
|
2
|
-
use crate::quantities::*;
|
|
3
2
|
|
|
4
3
|
#[cfg_attr(feature = "strum", derive(EnumIter))]
|
|
5
4
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
@@ -59,5 +58,3 @@ impl_quantity!(
|
|
|
59
58
|
[InverseDistanceUnit::_mm]
|
|
60
59
|
);
|
|
61
60
|
impl_div_with_self_to_f64!(InverseDistance);
|
|
62
|
-
|
|
63
|
-
impl_mul!(InverseDistance, Distance, f64);
|
|
@@ -25,7 +25,6 @@ impl PhysicsUnit for InverseStressUnit {
|
|
|
25
25
|
|
|
26
26
|
impl_quantity!(InverseStress, InverseStressUnit, [InverseStressUnit::_Pa]);
|
|
27
27
|
impl_div_with_self_to_f64!(InverseStress);
|
|
28
|
-
impl_mul!(InverseStress, Stress, f64);
|
|
29
28
|
|
|
30
29
|
impl Div<InverseStress> for f64 {
|
|
31
30
|
type Output = Stress;
|
|
@@ -40,8 +40,6 @@ impl PhysicsUnit for StressUnit {
|
|
|
40
40
|
|
|
41
41
|
impl_quantity!(Stress, StressUnit, [StressUnit::MPa]);
|
|
42
42
|
impl_div_with_self_to_f64!(Stress);
|
|
43
|
-
impl_div!(Stress, Strain, Stress);
|
|
44
|
-
impl_mul!(Stress, Strain, Stress);
|
|
45
43
|
|
|
46
44
|
impl Div<Stress> for f64 {
|
|
47
45
|
type Output = InverseStress;
|
|
@@ -55,6 +55,11 @@ impl_mul_relation_with_other!(AngularAcceleration, Density, MassDivTimeSquaredVo
|
|
|
55
55
|
impl_mul_relation_with_other!(MassDivTimeSquaredVolume, Area, Stress);
|
|
56
56
|
impl_mul_relation_with_other!(Force, Volume, ForceVolume);
|
|
57
57
|
impl_mul_relation_with_other!(Velocity, AngularVelocity, Acceleration);
|
|
58
|
+
impl_mul!(InverseDistance, Distance, f64);
|
|
59
|
+
impl_mul!(InverseAngle, Angle, f64);
|
|
60
|
+
impl_mul!(InverseStress, Stress, f64);
|
|
61
|
+
impl_div!(Stress, Strain, Stress);
|
|
62
|
+
impl_mul!(Stress, Strain, Stress);
|
|
58
63
|
|
|
59
64
|
impl_mul_relation_with_self!(Distance, Area);
|
|
60
65
|
impl_mul_relation_with_self!(Area, AreaOfMoment);
|
|
@@ -405,7 +405,10 @@ where
|
|
|
405
405
|
R: PhysicsQuantity,
|
|
406
406
|
{
|
|
407
407
|
pub fn inverse(&self) -> Option<Matrix3<R>> {
|
|
408
|
-
let det = self.det();
|
|
408
|
+
let det = self.det();
|
|
409
|
+
if det.is_nan() || det.as_f64().abs() < f64::EPSILON {
|
|
410
|
+
return None;
|
|
411
|
+
}
|
|
409
412
|
|
|
410
413
|
let a = self[(0, 0)];
|
|
411
414
|
let b = self[(0, 1)];
|
|
@@ -435,18 +438,7 @@ where
|
|
|
435
438
|
],
|
|
436
439
|
];
|
|
437
440
|
|
|
438
|
-
if (
|
|
439
|
-
+ inv[0][1]
|
|
440
|
-
+ inv[0][2]
|
|
441
|
-
+ inv[1][0]
|
|
442
|
-
+ inv[1][1]
|
|
443
|
-
+ inv[1][2]
|
|
444
|
-
+ inv[2][0]
|
|
445
|
-
+ inv[2][1]
|
|
446
|
-
+ inv[2][2])
|
|
447
|
-
.as_f64()
|
|
448
|
-
.is_nan()
|
|
449
|
-
{
|
|
441
|
+
if inv.iter().flatten().any(|entry| entry.is_nan()) {
|
|
450
442
|
None
|
|
451
443
|
} else {
|
|
452
444
|
Some(Matrix3::new(inv))
|
|
@@ -90,6 +90,18 @@ mod matrix3_tests {
|
|
|
90
90
|
assert!(diff.get_power() < -12);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
#[test]
|
|
94
|
+
fn test_inverse_singular_large_exponents_returns_none() {
|
|
95
|
+
let huge = Distance::from_exponential(1.0, i32::MAX / 2);
|
|
96
|
+
let zero = Distance::from_raw(0.0);
|
|
97
|
+
let one = Distance::from_raw(1.0);
|
|
98
|
+
let matrix: Matrix3<Distance> =
|
|
99
|
+
Matrix3::new([[one, zero, zero], [zero, huge, huge], [zero, huge, huge]]);
|
|
100
|
+
|
|
101
|
+
let inverse: Option<Matrix3<InverseDistance>> = matrix.inverse();
|
|
102
|
+
assert_eq!(inverse, None);
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
#[test]
|
|
94
106
|
fn test_dot() {
|
|
95
107
|
let matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
|
|
@@ -2,6 +2,21 @@ pub fn approx_eq(a: f64, b: f64, epsilon: f64) -> bool {
|
|
|
2
2
|
(a - b).abs() < epsilon
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
#[cfg(test)]
|
|
6
|
+
mod test_overflow_safety {
|
|
7
|
+
use unitforge::prelude::*;
|
|
8
|
+
use unitforge::quantities::{Distance, DistanceUnit};
|
|
9
|
+
|
|
10
|
+
#[test]
|
|
11
|
+
fn test_subtraction_with_large_powers_does_not_overflow() {
|
|
12
|
+
let lhs = Distance::from_exponential(1.0, i32::MAX);
|
|
13
|
+
let rhs = Distance::from_exponential(1.0, i32::MAX);
|
|
14
|
+
let diff = lhs - rhs;
|
|
15
|
+
|
|
16
|
+
assert_eq!(diff.to(DistanceUnit::m), 0.0);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
#[cfg(test)]
|
|
6
21
|
mod test_force {
|
|
7
22
|
use ndarray::{arr1, arr2};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|