1use super::helpers::impl_try_from;
7#[allow(unused_imports)]
8#[cfg(feature = "_float_f64")]
9use crate::ExtFloat;
10#[allow(unused_imports)]
11#[cfg(feature = "alloc")]
12use crate::{vec_ as vec, Vec};
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
18#[non_exhaustive]
19pub enum UnitSi {
20 Quetta,
22 Ronna,
24 Yotta,
26 Zetta,
28 Exa,
30 Peta,
32 Tera,
34 Giga,
36 Mega,
38 Kilo,
40 Hecto,
42 Deca,
44
45 #[default]
47 None,
48
49 Deci,
51 Centi,
53 Milli,
55 Micro,
57 Nano,
59 Pico,
61 Femto,
63 Atto,
65 Zepto,
67 Yocto,
69 Ronto,
71 Quecto,
73}
74
75#[allow(non_upper_case_globals)]
77impl UnitSi {
78 pub const Q: Self = Self::Quetta;
80 pub const R: Self = Self::Ronna;
82 pub const Y: Self = Self::Yotta;
84 pub const Z: Self = Self::Zetta;
86 pub const E: Self = Self::Exa;
88 pub const P: Self = Self::Peta;
90 pub const T: Self = Self::Tera;
92 pub const G: Self = Self::Giga;
94 pub const M: Self = Self::Mega;
96 pub const k: Self = Self::Kilo;
98 pub const K: Self = Self::Kilo;
100 pub const h: Self = Self::Hecto;
102 pub const H: Self = Self::Hecto;
104 pub const da: Self = Self::Deca;
106 pub const D: Self = Self::Deca;
108 pub const d: Self = Self::Deci;
111 pub const c: Self = Self::Centi;
113 pub const m: Self = Self::Milli;
115 pub const u: Self = Self::Micro;
117 pub const n: Self = Self::Nano;
119 pub const p: Self = Self::Pico;
121 pub const f: Self = Self::Femto;
123 pub const a: Self = Self::Atto;
125 pub const z: Self = Self::Zepto;
127 pub const y: Self = Self::Yocto;
129 pub const r: Self = Self::Ronto;
131 pub const q: Self = Self::Quecto;
133}
134
135impl UnitSi {
136 #[must_use]
145 pub const fn symbol(&self) -> &str {
146 match self {
147 UnitSi::Quetta => "Q",
148 UnitSi::Ronna => "R",
149 UnitSi::Yotta => "Y",
150 UnitSi::Zetta => "Z",
151 UnitSi::Exa => "E",
152 UnitSi::Peta => "P",
153 UnitSi::Tera => "T",
154 UnitSi::Giga => "G",
155 UnitSi::Mega => "M",
156 UnitSi::Kilo => "k",
157 UnitSi::Hecto => "H",
158 UnitSi::Deca => "D",
159 UnitSi::None => "",
160 UnitSi::Deci => "d",
161 UnitSi::Centi => "c",
162 UnitSi::Milli => "m",
163 UnitSi::Micro => "µ",
164 UnitSi::Nano => "n",
165 UnitSi::Pico => "p",
166 UnitSi::Femto => "f",
167 UnitSi::Atto => "a",
168 UnitSi::Zepto => "z",
169 UnitSi::Yocto => "y",
170 UnitSi::Ronto => "r",
171 UnitSi::Quecto => "q",
172 }
173 }
174 #[must_use]
176 pub const fn symbol_ascii(&self) -> &str {
177 match self {
178 UnitSi::Micro => "u",
179 _ => self.symbol(),
180 }
181 }
182
183 #[must_use]
185 pub const fn name(&self) -> &str {
186 match self {
187 UnitSi::Quetta => "quetta",
188 UnitSi::Ronna => "ronna",
189 UnitSi::Yotta => "yotta",
190 UnitSi::Zetta => "zetta",
191 UnitSi::Exa => "exa",
192 UnitSi::Peta => "peta",
193 UnitSi::Tera => "tera",
194 UnitSi::Giga => "giga",
195 UnitSi::Mega => "mega",
196 UnitSi::Kilo => "kilo",
197 UnitSi::Hecto => "hecto",
198 UnitSi::Deca => "deca",
199 UnitSi::None => "",
200 UnitSi::Deci => "deci",
201 UnitSi::Centi => "centi",
202 UnitSi::Milli => "milli",
203 UnitSi::Micro => "micro",
204 UnitSi::Nano => "nano",
205 UnitSi::Pico => "pico",
206 UnitSi::Femto => "femto",
207 UnitSi::Atto => "atoo",
208 UnitSi::Zepto => "zepto",
209 UnitSi::Yocto => "yocto",
210 UnitSi::Ronto => "ronto",
211 UnitSi::Quecto => "quecto",
212 }
213 }
214
215 pub const BASE: i32 = 10;
217
218 pub const fn exp(&self) -> i32 {
220 match self {
221 UnitSi::Quetta => 30,
222 UnitSi::Ronna => 27,
223 UnitSi::Yotta => 24,
224 UnitSi::Zetta => 21,
225 UnitSi::Exa => 18,
226 UnitSi::Peta => 15,
227 UnitSi::Tera => 12,
228 UnitSi::Giga => 9,
229 UnitSi::Mega => 6,
230 UnitSi::Kilo => 3,
231 UnitSi::Hecto => 2,
232 UnitSi::Deca => 1,
233 UnitSi::None => 0,
234 UnitSi::Deci => -1,
235 UnitSi::Centi => -2,
236 UnitSi::Milli => -3,
237 UnitSi::Micro => -6,
238 UnitSi::Nano => -9,
239 UnitSi::Pico => -12,
240 UnitSi::Femto => -15,
241 UnitSi::Atto => -18,
242 UnitSi::Zepto => -21,
243 UnitSi::Yocto => -24,
244 UnitSi::Ronto => -27,
245 UnitSi::Quecto => -30,
246 }
247 }
248
249 pub const fn factor(&self) -> f64 {
251 match self {
252 UnitSi::Quetta => 1e30,
253 UnitSi::Ronna => 1e27,
254 UnitSi::Yotta => 1e24,
255 UnitSi::Zetta => 1e21,
256 UnitSi::Exa => 1e18,
257 UnitSi::Peta => 1e15,
258 UnitSi::Tera => 1e12,
259 UnitSi::Giga => 1e9,
260 UnitSi::Kilo => 1e3,
261 UnitSi::Mega => 1e6,
262 UnitSi::Hecto => 1e2,
263 UnitSi::Deca => 1e1,
264 UnitSi::None => 1e0,
265 UnitSi::Deci => 1e-1,
266 UnitSi::Centi => 1e-2,
267 UnitSi::Milli => 1e-3,
268 UnitSi::Micro => 1e-6,
269 UnitSi::Nano => 1e-9,
270 UnitSi::Pico => 1e-12,
271 UnitSi::Femto => 1e-15,
272 UnitSi::Atto => 1e-18,
273 UnitSi::Zepto => 1e-21,
274 UnitSi::Yocto => 1e-24,
275 UnitSi::Ronto => 1e-27,
276 UnitSi::Quecto => 1e-30,
277 }
278 }
279
280 pub const fn factor_i64(&self) -> i64 {
289 match self {
290 UnitSi::Exa => 1_000_000_000_000_000_000,
291 UnitSi::Peta => 1_000_000_000_000_000,
292 UnitSi::Tera => 1_000_000_000_000,
293 UnitSi::Giga => 1_000_000_000,
294 UnitSi::Mega => 1_000_000,
295 UnitSi::Kilo => 1_000,
296 UnitSi::Hecto => 100,
297 UnitSi::Deca => 10,
298 UnitSi::None => 1,
299 UnitSi::Deci => -10,
300 UnitSi::Centi => -100,
301 UnitSi::Milli => -1_000,
302 UnitSi::Micro => -1_000_000,
303 UnitSi::Nano => -1_000_000_000,
304 UnitSi::Pico => -1_000_000_000_000,
305 UnitSi::Femto => -1_000_000_000_000_000,
306 UnitSi::Atto => -1_000_000_000_000_000_000,
307 _ => todo![],
308 }
309 }
310
311 pub const fn factor_i128(&self) -> i128 {
313 match self {
314 UnitSi::Quetta => 1_000_000_000_000_000_000_000_000_000_000,
315 UnitSi::Ronna => 1_000_000_000_000_000_000_000_000_000,
316 UnitSi::Yotta => 1_000_000_000_000_000_000_000_000,
317 UnitSi::Zetta => 1_000_000_000_000_000_000_000,
318 UnitSi::Zepto => -1_000_000_000_000_000_000_000,
319 UnitSi::Yocto => -1_000_000_000_000_000_000_000_000,
320 UnitSi::Ronto => -1_000_000_000_000_000_000_000_000_000,
321 UnitSi::Quecto => -1_000_000_000_000_000_000_000_000_000_000,
322 _ => self.factor_i64() as i128,
323 }
324 }
325
326 #[must_use]
329 pub fn convert(value: f64, from: Self, to: Self) -> f64 {
330 if from == to {
331 return value;
332 }
333 let (from_factor, to_factor) = (from.factor(), to.factor());
334 value * (from_factor / to_factor)
335 }
336
337 #[must_use]
340 pub fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64) {
341 if from == to {
342 return (value, 0);
343 }
344 let (from_factor, to_factor) = (from.factor_i64(), to.factor_i64());
345
346 let converted = if from_factor > 0 && to_factor > 0 {
348 value * from_factor / to_factor
349 } else if from_factor > 0 && to_factor < 0 {
350 value * from_factor * to_factor.abs()
351 } else if from_factor < 0 && to_factor > 0 {
352 value * from_factor.abs() / to_factor
353 } else {
354 value * from_factor.abs() * to_factor.abs()
355 };
356
357 let remainder = if from_factor > 0 && to_factor > 0 {
358 value * from_factor % to_factor
359 } else if from_factor > 0 && to_factor < 0 {
360 value * from_factor
361 } else if from_factor < 0 && to_factor > 0 {
362 value % to_factor
363 } else {
364 0 };
366
367 (converted, remainder)
368 }
369
370 #[must_use]
373 pub fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128) {
374 if from == to {
375 return (value, 0);
376 }
377 let (from_factor, to_factor) = (from.factor_i128(), to.factor_i128());
378
379 let converted = if from_factor > 0 && to_factor > 0 {
381 value * from_factor / to_factor
382 } else if from_factor > 0 && to_factor < 0 {
383 value * from_factor * to_factor.abs()
384 } else if from_factor < 0 && to_factor > 0 {
385 value * from_factor.abs() / to_factor
386 } else {
387 value * from_factor.abs() * to_factor.abs()
388 };
389
390 let remainder = if from_factor > 0 && to_factor > 0 {
391 value * from_factor % to_factor
392 } else if from_factor > 0 && to_factor < 0 {
393 value * from_factor
394 } else if from_factor < 0 && to_factor > 0 {
395 value % to_factor
396 } else {
397 0 };
399
400 (converted, remainder)
401 }
402
403 #[cfg(any(feature = "std", feature = "_float_f64"))]
406 #[cfg_attr(feature = "nightly_doc", doc(cfg(any(feature = "std", feature = "_float_f64"))))]
407 pub fn reduce(value: f64) -> (f64, Self) {
408 match value.abs() {
409 value if value >= UnitSi::Quetta.factor() => {
410 (value / UnitSi::Quetta.factor(), UnitSi::Quetta)
411 }
412 value if value >= UnitSi::Ronna.factor() => {
413 (value / UnitSi::Ronna.factor(), UnitSi::Ronna)
414 }
415 value if value >= UnitSi::Yotta.factor() => {
416 (value / UnitSi::Yotta.factor(), UnitSi::Yotta)
417 }
418 value if value >= UnitSi::Zetta.factor() => {
419 (value / UnitSi::Zetta.factor(), UnitSi::Zetta)
420 }
421 value if value >= UnitSi::Exa.factor() => (value / UnitSi::Exa.factor(), UnitSi::Exa),
422 value if value >= UnitSi::Peta.factor() => {
423 (value / UnitSi::Peta.factor(), UnitSi::Peta)
424 }
425 value if value >= UnitSi::Tera.factor() => {
426 (value / UnitSi::Tera.factor(), UnitSi::Tera)
427 }
428 value if value >= UnitSi::Giga.factor() => {
429 (value / UnitSi::Giga.factor(), UnitSi::Giga)
430 }
431 value if value >= UnitSi::Mega.factor() => {
432 (value / UnitSi::Mega.factor(), UnitSi::Mega)
433 }
434 value if value >= UnitSi::Kilo.factor() => {
435 (value / UnitSi::Kilo.factor(), UnitSi::Kilo)
436 }
437 value if value >= UnitSi::Hecto.factor() => {
438 (value / UnitSi::Hecto.factor(), UnitSi::Hecto)
439 }
440 value if value >= UnitSi::Deca.factor() => {
441 (value / UnitSi::Deca.factor(), UnitSi::Deca)
442 }
443 value if value >= UnitSi::Deci.factor() => {
445 (value / UnitSi::Deci.factor(), UnitSi::Deci)
446 }
447 value if value >= UnitSi::Centi.factor() => {
448 (value / UnitSi::Centi.factor(), UnitSi::Centi)
449 }
450 value if value >= UnitSi::Milli.factor() => {
451 (value / UnitSi::Milli.factor(), UnitSi::Milli)
452 }
453 value if value >= UnitSi::Micro.factor() => {
454 (value / UnitSi::Micro.factor(), UnitSi::Micro)
455 }
456 value if value >= UnitSi::Nano.factor() => {
457 (value / UnitSi::Nano.factor(), UnitSi::Nano)
458 }
459 value if value >= UnitSi::Pico.factor() => {
460 (value / UnitSi::Pico.factor(), UnitSi::Pico)
461 }
462 value if value >= UnitSi::Femto.factor() => {
463 (value / UnitSi::Femto.factor(), UnitSi::Femto)
464 }
465 value if value >= UnitSi::Atto.factor() => {
466 (value / UnitSi::Atto.factor(), UnitSi::Atto)
467 }
468 value if value >= UnitSi::Zepto.factor() => {
469 (value / UnitSi::Zepto.factor(), UnitSi::Zepto)
470 }
471 value if value >= UnitSi::Yocto.factor() => {
472 (value / UnitSi::Yocto.factor(), UnitSi::Yocto)
473 }
474 value if value >= UnitSi::Ronto.factor() => {
475 (value / UnitSi::Ronto.factor(), UnitSi::Ronto)
476 }
477 value if value >= UnitSi::Quecto.factor() => {
478 (value / UnitSi::Quecto.factor(), UnitSi::Quecto)
479 }
480 _ => (value, UnitSi::None),
481 }
482 }
483
484 pub const fn reduce_i64(value: i64) -> (i64, Self, i64) {
487 match value {
488 value if value >= UnitSi::Exa.factor_i64() => {
489 (value / UnitSi::Exa.factor_i64(), UnitSi::Exa, value % UnitSi::Exa.factor_i64())
490 }
491 value if value >= UnitSi::Peta.factor_i64() => {
492 (value / UnitSi::Peta.factor_i64(), UnitSi::Peta, value % UnitSi::Peta.factor_i64())
493 }
494 value if value >= UnitSi::Tera.factor_i64() => {
495 (value / UnitSi::Tera.factor_i64(), UnitSi::Tera, value % UnitSi::Tera.factor_i64())
496 }
497 value if value >= UnitSi::Giga.factor_i64() => {
498 (value / UnitSi::Giga.factor_i64(), UnitSi::Giga, value % UnitSi::Giga.factor_i64())
499 }
500 value if value >= UnitSi::Mega.factor_i64() => {
501 (value / UnitSi::Mega.factor_i64(), UnitSi::Mega, value % UnitSi::Mega.factor_i64())
502 }
503 value if value >= UnitSi::Kilo.factor_i64() => {
504 (value / UnitSi::Kilo.factor_i64(), UnitSi::Kilo, value % UnitSi::Kilo.factor_i64())
505 }
506 value if value >= UnitSi::Hecto.factor_i64() => (
507 value / UnitSi::Hecto.factor_i64(),
508 UnitSi::Hecto,
509 value % UnitSi::Hecto.factor_i64(),
510 ),
511 value if value >= UnitSi::Deca.factor_i64() => {
512 (value / UnitSi::Deca.factor_i64(), UnitSi::Deca, value % UnitSi::Deca.factor_i64())
513 }
514 value if value <= UnitSi::Atto.factor_i64() => {
515 (value * UnitSi::Atto.factor_i64().abs(), UnitSi::Atto, 0)
516 }
517 value if value <= UnitSi::Femto.factor_i64() => {
518 (value * UnitSi::Femto.factor_i64().abs(), UnitSi::Femto, 0)
519 }
520 value if value <= UnitSi::Pico.factor_i64() => {
521 (value * UnitSi::Pico.factor_i64().abs(), UnitSi::Pico, 0)
522 }
523 value if value <= UnitSi::Nano.factor_i64() => {
524 (value * UnitSi::Nano.factor_i64().abs(), UnitSi::Nano, 0)
525 }
526 value if value <= UnitSi::Micro.factor_i64() => {
527 (value * UnitSi::Micro.factor_i64().abs(), UnitSi::Micro, 0)
528 }
529 value if value <= UnitSi::Milli.factor_i64() => {
530 (value * UnitSi::Milli.factor_i64().abs(), UnitSi::Milli, 0)
531 }
532 value if value <= UnitSi::Centi.factor_i64() => {
533 (value * UnitSi::Centi.factor_i64().abs(), UnitSi::Centi, 0)
534 }
535 value if value <= UnitSi::Deci.factor_i64() => {
536 (value * UnitSi::Deci.factor_i64().abs(), UnitSi::Deci, 0)
537 }
538 _ => (value, UnitSi::None, 0),
539 }
540 }
541
542 pub const fn reduce_i128(value: i128) -> (i128, Self, i128) {
545 match value {
546 value if value >= UnitSi::Quetta.factor_i128() => (
547 value / UnitSi::Quetta.factor_i128(),
548 UnitSi::Quetta,
549 value % UnitSi::Quetta.factor_i128(),
550 ),
551 value if value >= UnitSi::Ronna.factor_i128() => (
552 value / UnitSi::Ronna.factor_i128(),
553 UnitSi::Ronna,
554 value % UnitSi::Ronna.factor_i128(),
555 ),
556 value if value >= UnitSi::Yotta.factor_i128() => (
557 value / UnitSi::Yotta.factor_i128(),
558 UnitSi::Yotta,
559 value % UnitSi::Yotta.factor_i128(),
560 ),
561 value if value >= UnitSi::Zetta.factor_i128() => (
562 value / UnitSi::Zetta.factor_i128(),
563 UnitSi::Zetta,
564 value % UnitSi::Zetta.factor_i128(),
565 ),
566 value if value <= UnitSi::Quecto.factor_i128() => {
567 (value * UnitSi::Quecto.factor_i128().abs(), UnitSi::Quecto, 0)
568 }
569 value if value <= UnitSi::Ronto.factor_i128() => {
570 (value * UnitSi::Ronto.factor_i128().abs(), UnitSi::Ronto, 0)
571 }
572 value if value <= UnitSi::Yocto.factor_i128() => {
573 (value * UnitSi::Yocto.factor_i128().abs(), UnitSi::Yocto, 0)
574 }
575 value if value <= UnitSi::Zepto.factor_i128() => {
576 (value * UnitSi::Zepto.factor_i128().abs(), UnitSi::Zepto, 0)
577 }
578 _ => {
579 let (v, p, r) = Self::reduce_i64(value as i64);
580 (v as i128, p, r as i128)
581 }
582 }
583 }
584
585 #[must_use]
588 #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
589 #[cfg_attr(
590 feature = "nightly_doc",
591 doc(cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64"))))
592 )]
593 pub fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)> {
594 if value == 0.0 {
595 return vec![(0.0, UnitSi::None)];
596 }
597
598 let mut result = Vec::new();
599 let mut remainder = value;
600
601 let effective_threshold =
604 if threshold <= 0.0 { crate::ExtFloatConst::MEDIUM_MARGIN } else { threshold };
605
606 while remainder.abs() > effective_threshold {
607 let (size, unit) = Self::reduce(remainder);
608 let integer_part = size.trunc();
609 let fractional_part = size - integer_part;
610 result.push((integer_part, unit));
611 remainder = fractional_part * unit.factor();
612
613 if remainder.abs() < effective_threshold {
614 break;
615 }
616 }
617 if remainder.abs() >= effective_threshold {
618 result.push((remainder, UnitSi::None));
619 }
620 result
621 }
622
623 #[must_use]
626 #[cfg(feature = "alloc")]
627 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
628 pub fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)> {
629 let mut result = Vec::new();
630 let mut remainder = value;
631
632 while remainder.abs() > threshold.abs() {
633 let (size, unit, new_remainder) = Self::reduce_i64(remainder);
634 result.push((size, unit));
635 remainder = new_remainder;
636
637 if remainder.abs() < threshold.abs() {
638 break;
639 }
640 }
641 if remainder.abs() >= threshold.abs() {
642 result.push((remainder, UnitSi::None));
643 }
644 result
645 }
646
647 #[must_use]
650 #[cfg(feature = "alloc")]
651 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
652 pub fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)> {
653 let mut result = Vec::new();
654 let mut remainder = value;
655
656 while remainder.abs() > threshold.abs() {
657 let (size, unit, new_remainder) = Self::reduce_i128(remainder);
658 result.push((size, unit));
659 remainder = new_remainder;
660
661 if remainder.abs() < threshold.abs() {
662 break;
663 }
664 }
665 if remainder.abs() >= threshold.abs() {
666 result.push((remainder, UnitSi::None));
667 }
668 result
669 }
670}
671
672impl UnitSi {
673 pub fn asc_iter() -> impl Iterator<Item = Self> {
675 const UNITS: [UnitSi; 25] = [
676 UnitSi::Quecto,
677 UnitSi::Ronto,
678 UnitSi::Yocto,
679 UnitSi::Zepto,
680 UnitSi::Atto,
681 UnitSi::Femto,
682 UnitSi::Pico,
683 UnitSi::Nano,
684 UnitSi::Micro,
685 UnitSi::Milli,
686 UnitSi::Centi,
687 UnitSi::Deci,
688 UnitSi::None,
689 UnitSi::Deca,
690 UnitSi::Hecto,
691 UnitSi::Kilo,
692 UnitSi::Mega,
693 UnitSi::Giga,
694 UnitSi::Tera,
695 UnitSi::Peta,
696 UnitSi::Exa,
697 UnitSi::Zetta,
698 UnitSi::Yotta,
699 UnitSi::Ronna,
700 UnitSi::Quetta,
701 ];
702 UNITS.iter().copied()
703 }
704
705 pub fn desc_iter() -> impl Iterator<Item = Self> {
707 const UNITS: [UnitSi; 25] = [
708 UnitSi::Quetta,
709 UnitSi::Ronna,
710 UnitSi::Yotta,
711 UnitSi::Zetta,
712 UnitSi::Exa,
713 UnitSi::Peta,
714 UnitSi::Tera,
715 UnitSi::Giga,
716 UnitSi::Mega,
717 UnitSi::Kilo,
718 UnitSi::Hecto,
719 UnitSi::Deca,
720 UnitSi::None,
721 UnitSi::Deci,
722 UnitSi::Centi,
723 UnitSi::Milli,
724 UnitSi::Micro,
725 UnitSi::Nano,
726 UnitSi::Pico,
727 UnitSi::Femto,
728 UnitSi::Atto,
729 UnitSi::Zepto,
730 UnitSi::Yocto,
731 UnitSi::Ronto,
732 UnitSi::Quecto,
733 ];
734 UNITS.iter().copied()
735 }
736}
737
738impl From<UnitSi> for f32 {
739 fn from(from: UnitSi) -> f32 {
740 from.factor() as f32
741 }
742}
743impl From<UnitSi> for f64 {
744 fn from(from: UnitSi) -> f64 {
745 from.factor()
746 }
747}
748impl From<UnitSi> for i64 {
749 fn from(from: UnitSi) -> i64 {
750 from.factor_i64()
751 }
752}
753impl From<UnitSi> for i128 {
754 fn from(from: UnitSi) -> i128 {
755 from.factor_i128()
756 }
757}
758impl_try_from![UnitSi, i64 => i32, i16, u64, u32, u16];
759impl_try_from![UnitSi, i128 => u128];
760
761#[cfg(test)]
762mod tests {
763 #![allow(unused_imports)]
764 use super::{
765 UnitSi,
766 UnitSi::{
767 Centi, Deca, Deci, Giga, Hecto, Kilo, Mega, Micro, Milli, Nano, Quetta, Ronna, Tera,
768 Yotta, Zetta,
769 },
770 };
771 #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
772 use crate::vec_ as vec;
773 use crate::{code::sf, num::ExtFloatConst};
774
775 #[test]
778 fn unit_si_reduce_i64() {
779 let value = 4 * i64::from(Tera);
780 let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
781 assert_eq!(reduced_value, 4);
782 assert_eq!(unit, Tera);
783 assert_eq!(remainder, 0);
784
785 let value = 15 * i64::from(Kilo) + 500; let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
787 assert_eq!(reduced_value, 15);
788 assert_eq!(unit, Kilo);
789 assert_eq!(remainder, 500);
790
791 let value = 1; let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
793 assert_eq!(reduced_value, 1);
794 assert_eq!(unit, UnitSi::None);
795 assert_eq!(remainder, 0);
796
797 let value = 999;
798 let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
799 assert_eq!(reduced_value, 9);
800 assert_eq!(unit, Hecto);
801 assert_eq!(remainder, 99);
802 }
803
804 #[test]
805 fn unit_si_reduce_i128() {
806 let value = 3000 * i128::from(Ronna) + 5 * i128::from(Mega);
807 let (reduced_value, unit, remainder) = UnitSi::reduce_i128(value);
808 assert_eq!(reduced_value, 3);
809 assert_eq!(unit, Quetta);
810 assert_eq!(remainder, 5 * i128::from(Mega));
811
812 let value = 900_033; let (reduced_value, unit, remainder) = UnitSi::reduce_i128(value);
814 assert_eq!(reduced_value, 900);
815 assert_eq!(unit, Kilo);
816 assert_eq!(remainder, 33);
817 }
818
819 #[test]
822 #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
823 #[cfg_attr(
824 feature = "nightly_doc",
825 doc(cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64"))))
826 )]
827 fn unit_si_reduce_chain() {
828 let margin = f64::MEDIUM_MARGIN;
829
830 assert_eq![
831 UnitSi::reduce_chain(Giga.factor(), margin),
833 vec![(1.0, Giga)]
834 ];
835 assert_eq![
836 UnitSi::reduce_chain(1.5 * Giga.factor(), margin),
838 vec![(1.0, Giga), (500.0, Mega)]
839 ];
840 assert_eq![
841 UnitSi::reduce_chain(Giga.factor() + Kilo.factor(), margin),
843 sf! { vec![
845 (1.0, Giga), (9.0, Hecto), (9.0, Deca), (99.0, Deci),
846 (9.0, Centi), (9.0, Milli), (999.0, Micro), (917.0, Nano)
847 ]}
848 ];
849 assert_eq![
850 UnitSi::reduce_chain(Mega.factor() / 2.0, margin),
852 vec![(500.0, Kilo)]
853 ];
854 assert_eq![
855 UnitSi::reduce_chain(Yotta.factor() + Zetta.factor() + Giga.factor(), margin),
857 sf! { vec![
859 (1.0, Yotta), (1.0, Zetta), (1.0, Giga), (88.0, Kilo), (9.0, Hecto),
860 (5.0, Deci), (8.0, Centi), (2.0, Milli), (341.0, Micro), (11.0, Nano)
861 ]}
862 ];
863 assert_eq![
864 UnitSi::reduce_chain(0.0, margin),
866 vec![(0.0, UnitSi::None)]
867 ];
868 assert_eq![
869 UnitSi::reduce_chain(Giga.factor() / 2., margin),
871 vec![(500., Mega)]
872 ];
873 }
874}