Skip to main content

libsurfer/translation/
numeric_translators.rs

1use crate::message::Message;
2use crate::translation::fixed_point::{big_uint_to_sfixed, big_uint_to_ufixed};
3use crate::variable_meta::VariableMetaExt;
4use crate::wave_container::{ScopeId, VarId};
5use eyre::Result;
6use half::{bf16, f16};
7use num::{BigUint, One};
8use softposit::{P8E0, P16E1, P32E2, Q8E0, Q16E1};
9use surfer_translation_types::{
10    BasicTranslator, TranslationResult, Translator, ValueKind, ValueRepr, VariableInfo,
11    VariableMeta, VariableValue, biguint_to_f64, parse_value_to_numeric, translates_all_bit_types,
12};
13
14use super::{TranslationPreference, check_single_wordlength};
15
16#[inline]
17fn shortest_float_representation<T: std::fmt::LowerExp + std::fmt::Display>(v: T) -> String {
18    let dec = format!("{v}");
19    let exp = format!("{v:e}");
20    if dec.len() > exp.len() { exp } else { dec }
21}
22
23/// If `value` is a biguint or consists only of 1 or 0, translates the value using
24/// `biguint_translator`. If `value` contains other values such as X, Z etc. the result
25/// is the corresponding `ValueKind`
26fn translate_numeric(
27    biguint_translator: impl Fn(&BigUint) -> String,
28    value: &VariableValue,
29) -> (String, ValueKind) {
30    match value.parse_biguint() {
31        Ok(v) => (biguint_translator(&v), ValueKind::Normal),
32        Err((v, k)) => (v, k),
33    }
34}
35
36pub struct UnsignedTranslator {}
37
38impl BasicTranslator<VarId, ScopeId> for UnsignedTranslator {
39    fn name(&self) -> String {
40        String::from("Unsigned")
41    }
42
43    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
44        translate_numeric(std::string::ToString::to_string, v)
45    }
46
47    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
48        Some(parse_value_to_numeric(value, biguint_to_f64))
49    }
50
51    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
52        if variable.has_unsigned_integer_type_name() {
53            Ok(TranslationPreference::Prefer)
54        } else {
55            translates_all_bit_types(variable)
56        }
57    }
58}
59
60pub struct SignedTranslator {}
61
62impl BasicTranslator<VarId, ScopeId> for SignedTranslator {
63    fn name(&self) -> String {
64        String::from("Signed")
65    }
66
67    fn basic_translate(&self, num_bits: u32, v: &VariableValue) -> (String, ValueKind) {
68        translate_numeric(|val| compute_signed_value(val, num_bits), v)
69    }
70
71    fn basic_translate_numeric(&self, num_bits: u32, value: &VariableValue) -> Option<f64> {
72        Some(parse_value_to_numeric(value, |v| {
73            let signweight = BigUint::one() << (num_bits - 1);
74            if v < &signweight {
75                biguint_to_f64(v)
76            } else {
77                let v2 = (&signweight << 1) - v;
78                -biguint_to_f64(&v2)
79            }
80        }))
81    }
82
83    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
84        if variable.is_integer_type() || variable.has_signed_integer_type_name() {
85            Ok(TranslationPreference::Prefer)
86        } else {
87            translates_all_bit_types(variable)
88        }
89    }
90}
91
92/// Computes the signed value string for a given `BigUint` and bit width.
93fn compute_signed_value(v: &BigUint, num_bits: u32) -> String {
94    let signweight = BigUint::one() << (num_bits - 1);
95    if v < &signweight {
96        v.to_string()
97    } else {
98        let v2 = (signweight << 1) - v;
99        format!("-{v2}")
100    }
101}
102
103pub struct SinglePrecisionTranslator {}
104
105impl BasicTranslator<VarId, ScopeId> for SinglePrecisionTranslator {
106    fn name(&self) -> String {
107        String::from("FP: 32-bit IEEE 754")
108    }
109
110    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
111        translate_numeric(
112            |v| {
113                shortest_float_representation(f32::from_bits(
114                    v.iter_u32_digits().next().unwrap_or(0),
115                ))
116            },
117            v,
118        )
119    }
120
121    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
122        Some(parse_value_to_numeric(value, |v| {
123            f64::from(f32::from_bits(v.iter_u32_digits().next().unwrap_or(0)))
124        }))
125    }
126
127    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
128        check_single_wordlength(variable.num_bits, 32)
129    }
130}
131
132pub struct DoublePrecisionTranslator {}
133
134impl BasicTranslator<VarId, ScopeId> for DoublePrecisionTranslator {
135    fn name(&self) -> String {
136        String::from("FP: 64-bit IEEE 754")
137    }
138    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
139        translate_numeric(
140            |v| {
141                shortest_float_representation(f64::from_bits(
142                    v.iter_u64_digits().next().unwrap_or(0),
143                ))
144            },
145            v,
146        )
147    }
148    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
149        Some(parse_value_to_numeric(value, |v| {
150            f64::from_bits(v.iter_u64_digits().next().unwrap_or(0))
151        }))
152    }
153    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
154        if variable.is_real() {
155            Ok(TranslationPreference::Prefer)
156        } else {
157            check_single_wordlength(variable.num_bits, 64)
158        }
159    }
160}
161
162#[cfg(feature = "f128")]
163pub struct QuadPrecisionTranslator {}
164
165#[cfg(feature = "f128")]
166impl BasicTranslator<VarId, ScopeId> for QuadPrecisionTranslator {
167    fn name(&self) -> String {
168        String::from("FP: 128-bit IEEE 754")
169    }
170    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
171        translate_numeric(
172            |v| {
173                let mut digits = v.iter_u64_digits();
174                let lsb = digits.next().unwrap_or(0);
175                let msb = if digits.len() > 0 {
176                    digits.next().unwrap_or(0)
177                } else {
178                    0
179                };
180                let val = lsb as u128 | (msb as u128) << 64;
181                f128::f128::from_bits(val).to_string()
182            },
183            v,
184        )
185    }
186    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
187        check_single_wordlength(variable.num_bits, 128)
188    }
189}
190
191pub struct HalfPrecisionTranslator {}
192
193impl BasicTranslator<VarId, ScopeId> for HalfPrecisionTranslator {
194    fn name(&self) -> String {
195        String::from("FP: 16-bit IEEE 754")
196    }
197    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
198        translate_numeric(
199            |v| {
200                shortest_float_representation(f16::from_bits(
201                    v.iter_u32_digits().next().unwrap_or(0) as u16,
202                ))
203            },
204            v,
205        )
206    }
207    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
208        Some(parse_value_to_numeric(value, |v| {
209            f64::from(f16::from_bits(
210                v.iter_u32_digits().next().unwrap_or(0) as u16
211            ))
212        }))
213    }
214    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
215        check_single_wordlength(variable.num_bits, 16)
216    }
217}
218
219pub struct BFloat16Translator {}
220
221impl BasicTranslator<VarId, ScopeId> for BFloat16Translator {
222    fn name(&self) -> String {
223        String::from("FP: bfloat16")
224    }
225    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
226        translate_numeric(
227            |v| {
228                shortest_float_representation(bf16::from_bits(
229                    v.iter_u32_digits().next().unwrap_or(0) as u16,
230                ))
231            },
232            v,
233        )
234    }
235    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
236        Some(parse_value_to_numeric(value, |v| {
237            f64::from(bf16::from_bits(
238                v.iter_u32_digits().next().unwrap_or(0) as u16
239            ))
240        }))
241    }
242    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
243        check_single_wordlength(variable.num_bits, 16)
244    }
245}
246
247pub struct Posit32Translator {}
248
249impl BasicTranslator<VarId, ScopeId> for Posit32Translator {
250    fn name(&self) -> String {
251        String::from("Posit: 32-bit (two exponent bits)")
252    }
253
254    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
255        translate_numeric(
256            |v| {
257                format!(
258                    "{p}",
259                    p = P32E2::from_bits(v.iter_u32_digits().next().unwrap_or(0))
260                )
261            },
262            v,
263        )
264    }
265
266    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
267        Some(parse_value_to_numeric(value, |v| {
268            P32E2::from_bits(v.iter_u32_digits().next().unwrap_or(0)).into()
269        }))
270    }
271
272    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
273        check_single_wordlength(variable.num_bits, 32)
274    }
275}
276
277pub struct Posit16Translator {}
278
279impl BasicTranslator<VarId, ScopeId> for Posit16Translator {
280    fn name(&self) -> String {
281        String::from("Posit: 16-bit (one exponent bit)")
282    }
283
284    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
285        translate_numeric(
286            |v| {
287                format!(
288                    "{p}",
289                    p = P16E1::from_bits(v.iter_u32_digits().next().unwrap_or(0) as u16)
290                )
291            },
292            v,
293        )
294    }
295
296    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
297        Some(parse_value_to_numeric(value, |v| {
298            P16E1::from_bits(v.iter_u32_digits().next().unwrap_or(0) as u16).into()
299        }))
300    }
301
302    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
303        check_single_wordlength(variable.num_bits, 16)
304    }
305}
306
307pub struct Posit8Translator {}
308
309impl BasicTranslator<VarId, ScopeId> for Posit8Translator {
310    fn name(&self) -> String {
311        String::from("Posit: 8-bit (no exponent bit)")
312    }
313
314    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
315        translate_numeric(
316            |v| {
317                format!(
318                    "{p}",
319                    p = P8E0::from_bits(v.iter_u32_digits().next().unwrap_or(0) as u8)
320                )
321            },
322            v,
323        )
324    }
325
326    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
327        Some(parse_value_to_numeric(value, |v| {
328            P8E0::from_bits(v.iter_u32_digits().next().unwrap_or(0) as u8).into()
329        }))
330    }
331
332    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
333        check_single_wordlength(variable.num_bits, 8)
334    }
335}
336
337pub struct PositQuire8Translator {}
338
339impl BasicTranslator<VarId, ScopeId> for PositQuire8Translator {
340    fn name(&self) -> String {
341        String::from("Posit: quire for 8-bit (no exponent bit)")
342    }
343
344    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
345        translate_numeric(
346            |v| {
347                format!(
348                    "{p}",
349                    p = Q8E0::from_bits(v.iter_u32_digits().next().unwrap_or(0))
350                )
351            },
352            v,
353        )
354    }
355
356    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
357        Some(parse_value_to_numeric(value, |v| {
358            let q = Q8E0::from_bits(v.iter_u32_digits().next().unwrap_or(0));
359            P8E0::from(q).into()
360        }))
361    }
362
363    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
364        check_single_wordlength(variable.num_bits, 32)
365    }
366}
367
368pub struct PositQuire16Translator {}
369
370impl BasicTranslator<VarId, ScopeId> for PositQuire16Translator {
371    fn name(&self) -> String {
372        String::from("Posit: quire for 16-bit (one exponent bit)")
373    }
374
375    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
376        translate_numeric(
377            |v| {
378                let mut digits = v.iter_u64_digits();
379                let lsb = digits.next().unwrap_or(0);
380                let msb = digits.next().unwrap_or(0);
381                let val = u128::from(lsb) | (u128::from(msb) << 64);
382                format!("{}", Q16E1::from_bits(val))
383            },
384            v,
385        )
386    }
387
388    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
389        Some(parse_value_to_numeric(value, |v| {
390            let mut digits = v.iter_u64_digits();
391            let lsb = digits.next().unwrap_or(0);
392            let msb = digits.next().unwrap_or(0);
393            let val = u128::from(lsb) | (u128::from(msb) << 64);
394            P16E1::from(Q16E1::from_bits(val)).into()
395        }))
396    }
397
398    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
399        check_single_wordlength(variable.num_bits, 128)
400    }
401}
402
403/// Format an f64 value as a string for FP8 display.
404///
405/// Handles special cases: NaN, infinity (with sign), and signed zero.
406/// Normal values use the shortest representation (decimal or scientific).
407fn format_fp8_value(v: f64) -> String {
408    if v.is_nan() {
409        "NaN".to_string()
410    } else if v.is_infinite() {
411        if v.is_sign_negative() {
412            "-∞".to_string()
413        } else {
414            "∞".to_string()
415        }
416    } else if v == 0.0 {
417        if v.is_sign_negative() {
418            "-0".to_string()
419        } else {
420            "0".to_string()
421        }
422    } else {
423        shortest_float_representation(v as f32)
424    }
425}
426
427/// Decode u8 as 8-bit float with five exponent bits and two mantissa bits, returning f64.
428#[allow(clippy::excessive_precision)]
429fn decode_e5m2_f64(v: u8) -> f64 {
430    let mant = v & 3;
431    let exp = (v >> 2) & 31;
432    let sign: f64 = if (v >> 7) != 0 { -1.0 } else { 1.0 };
433    match (exp, mant) {
434        (31, 0) => sign * f64::INFINITY,
435        (31, ..) => f64::NAN,
436        (0, 0) => sign * 0.0,
437        (0, ..) => sign * f64::from(mant) * 0.0000152587890625f64, // 2^-16
438        _ => sign * f64::from(4 + mant) * 2.0f64.powi(i32::from(exp) - 17),
439    }
440}
441
442/// Decode u8 as 8-bit float with four exponent bits and three mantissa bits, returning f64.
443fn decode_e4m3_f64(v: u8) -> f64 {
444    let mant = v & 7;
445    let exp = (v >> 3) & 15;
446    let sign: f64 = if (v >> 7) != 0 { -1.0 } else { 1.0 };
447    match (exp, mant) {
448        (15, 7) => f64::NAN,
449        (0, 0) => sign * 0.0,
450        (0, ..) => sign * f64::from(mant) * 0.001953125f64, // 2^-9
451        _ => sign * f64::from(8 + mant) * 2.0f64.powi(i32::from(exp) - 10),
452    }
453}
454
455/// Decode u8 as 8-bit float with five exponent bits and two mantissa bits.
456fn decode_e5m2(v: u8) -> String {
457    format_fp8_value(decode_e5m2_f64(v))
458}
459
460pub struct E5M2Translator {}
461
462impl BasicTranslator<VarId, ScopeId> for E5M2Translator {
463    fn name(&self) -> String {
464        String::from("FP: 8-bit (E5M2)")
465    }
466
467    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
468        translate_numeric(
469            |v| decode_e5m2(v.iter_u32_digits().next().unwrap_or(0) as u8),
470            v,
471        )
472    }
473
474    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
475        Some(parse_value_to_numeric(value, |v| {
476            decode_e5m2_f64(v.iter_u32_digits().next().unwrap_or(0) as u8)
477        }))
478    }
479
480    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
481        check_single_wordlength(variable.num_bits, 8)
482    }
483}
484
485/// Decode u8 as 8-bit float with four exponent bits and three mantissa bits.
486fn decode_e4m3(v: u8) -> String {
487    format_fp8_value(decode_e4m3_f64(v))
488}
489
490pub struct E4M3Translator {}
491
492impl BasicTranslator<VarId, ScopeId> for E4M3Translator {
493    fn name(&self) -> String {
494        String::from("FP: 8-bit (E4M3)")
495    }
496
497    fn basic_translate(&self, _: u32, v: &VariableValue) -> (String, ValueKind) {
498        translate_numeric(
499            |v| decode_e4m3(v.iter_u32_digits().next().unwrap_or(0) as u8),
500            v,
501        )
502    }
503
504    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
505        Some(parse_value_to_numeric(value, |v| {
506            decode_e4m3_f64(v.iter_u32_digits().next().unwrap_or(0) as u8)
507        }))
508    }
509
510    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
511        check_single_wordlength(variable.num_bits, 8)
512    }
513}
514
515pub struct UnsignedFixedPointTranslator;
516
517impl Translator<VarId, ScopeId, Message> for UnsignedFixedPointTranslator {
518    fn name(&self) -> String {
519        "Unsigned fixed point".into()
520    }
521
522    fn translate(
523        &self,
524        variable: &VariableMeta<VarId, ScopeId>,
525        value: &VariableValue,
526    ) -> Result<TranslationResult> {
527        let (string, value_kind) = if let Some(idx) = &variable.index {
528            translate_numeric(|v| big_uint_to_ufixed(v, -idx.lsb), value)
529        } else {
530            translate_numeric(std::string::ToString::to_string, value)
531        };
532        Ok(TranslationResult {
533            kind: value_kind,
534            val: ValueRepr::String(string),
535            subfields: vec![],
536        })
537    }
538
539    fn variable_info(&self, _: &VariableMeta<VarId, ScopeId>) -> Result<VariableInfo> {
540        Ok(VariableInfo::Bits)
541    }
542
543    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
544        if variable.has_unsigned_fixedpoint_type_name() {
545            Ok(TranslationPreference::Prefer)
546        } else {
547            translates_all_bit_types(variable)
548        }
549    }
550}
551
552pub struct SignedFixedPointTranslator;
553
554impl Translator<VarId, ScopeId, Message> for SignedFixedPointTranslator {
555    fn name(&self) -> String {
556        "Signed fixed point".into()
557    }
558
559    fn translate(
560        &self,
561        variable: &VariableMeta<VarId, ScopeId>,
562        value: &VariableValue,
563    ) -> Result<TranslationResult> {
564        let (string, value_kind) = if let Some(idx) = &variable.index {
565            translate_numeric(
566                |v| big_uint_to_sfixed(v, u64::from(variable.num_bits.unwrap_or(0)), -idx.lsb),
567                value,
568            )
569        } else {
570            translate_numeric(std::string::ToString::to_string, value)
571        };
572        Ok(TranslationResult {
573            kind: value_kind,
574            val: ValueRepr::String(string),
575            subfields: vec![],
576        })
577    }
578
579    fn variable_info(&self, _: &VariableMeta<VarId, ScopeId>) -> Result<VariableInfo> {
580        Ok(VariableInfo::Bits)
581    }
582
583    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
584        if variable.has_signed_fixedpoint_type_name() {
585            Ok(TranslationPreference::Prefer)
586        } else {
587            translates_all_bit_types(variable)
588        }
589    }
590}
591
592#[cfg(test)]
593mod test {
594    use super::*;
595    use surfer_translation_types::VariableValue;
596
597    #[test]
598    fn signed_translation_from_string() {
599        assert_eq!(
600            SignedTranslator {}
601                .basic_translate(5, &VariableValue::String("10000".to_string()))
602                .0,
603            "-16"
604        );
605
606        assert_eq!(
607            SignedTranslator {}
608                .basic_translate(5, &VariableValue::String("01000".to_string()))
609                .0,
610            "8"
611        );
612    }
613
614    #[test]
615    fn signed_translation_from_biguint() {
616        assert_eq!(
617            SignedTranslator {}
618                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b10011u32)))
619                .0,
620            "-13"
621        );
622
623        assert_eq!(
624            SignedTranslator {}
625                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b01000u32)))
626                .0,
627            "8"
628        );
629        assert_eq!(
630            SignedTranslator {}
631                .basic_translate(2, &VariableValue::BigUint(BigUint::from(0u32)))
632                .0,
633            "0"
634        );
635    }
636
637    #[test]
638    fn unsigned_translation_from_string() {
639        assert_eq!(
640            UnsignedTranslator {}
641                .basic_translate(5, &VariableValue::String("10000".to_string()))
642                .0,
643            "16"
644        );
645
646        assert_eq!(
647            UnsignedTranslator {}
648                .basic_translate(5, &VariableValue::String("01000".to_string()))
649                .0,
650            "8"
651        );
652    }
653
654    #[test]
655    fn unsigned_translation_from_biguint() {
656        assert_eq!(
657            UnsignedTranslator {}
658                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b10011u32)))
659                .0,
660            "19"
661        );
662
663        assert_eq!(
664            UnsignedTranslator {}
665                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b01000u32)))
666                .0,
667            "8"
668        );
669        assert_eq!(
670            UnsignedTranslator {}
671                .basic_translate(2, &VariableValue::BigUint(BigUint::from(0u32)))
672                .0,
673            "0"
674        );
675    }
676
677    #[test]
678    fn e4m3_translation_from_biguint() {
679        assert_eq!(
680            E4M3Translator {}
681                .basic_translate(8, &VariableValue::BigUint(BigUint::from(0b10001000u8)))
682                .0,
683            "-0.015625"
684        );
685    }
686
687    #[test]
688    fn e4m3_translation_from_string() {
689        assert_eq!(
690            E4M3Translator {}
691                .basic_translate(8, &VariableValue::String("11111111".to_string()))
692                .0,
693            "NaN"
694        );
695        assert_eq!(
696            E4M3Translator {}
697                .basic_translate(8, &VariableValue::String("00000011".to_string()))
698                .0,
699            "0.005859375"
700        );
701        assert_eq!(
702            E4M3Translator {}
703                .basic_translate(8, &VariableValue::String("10000000".to_string()))
704                .0,
705            "-0"
706        );
707        assert_eq!(
708            E4M3Translator {}
709                .basic_translate(8, &VariableValue::String("00000000".to_string()))
710                .0,
711            "0"
712        );
713        assert_eq!(
714            E4M3Translator {}
715                .basic_translate(8, &VariableValue::String("11110111".to_string()))
716                .0,
717            "-240"
718        );
719        assert_eq!(
720            E4M3Translator {}
721                .basic_translate(8, &VariableValue::String("01000000".to_string()))
722                .0,
723            "2"
724        );
725    }
726
727    #[test]
728    fn e5m2_translation_from_biguint() {
729        assert_eq!(
730            E5M2Translator {}
731                .basic_translate(8, &VariableValue::BigUint(BigUint::from(0b10000100u8)))
732                .0,
733            "-6.1035156e-5"
734        );
735        assert_eq!(
736            E5M2Translator {}
737                .basic_translate(8, &VariableValue::BigUint(BigUint::from(0b11111100u8)))
738                .0,
739            "-∞"
740        );
741    }
742
743    #[test]
744    fn e5m2_translation_from_string() {
745        assert_eq!(
746            E5M2Translator {}
747                .basic_translate(8, &VariableValue::String("11111111".to_string()))
748                .0,
749            "NaN"
750        );
751        assert_eq!(
752            E5M2Translator {}
753                .basic_translate(8, &VariableValue::String("00000011".to_string()))
754                .0,
755            "4.5776367e-5"
756        );
757        assert_eq!(
758            E5M2Translator {}
759                .basic_translate(8, &VariableValue::String("10000000".to_string()))
760                .0,
761            "-0"
762        );
763        assert_eq!(
764            E5M2Translator {}
765                .basic_translate(8, &VariableValue::String("00000000".to_string()))
766                .0,
767            "0"
768        );
769        assert_eq!(
770            E5M2Translator {}
771                .basic_translate(8, &VariableValue::String("11111011".to_string()))
772                .0,
773            "-57344"
774        );
775        assert_eq!(
776            E5M2Translator {}
777                .basic_translate(8, &VariableValue::String("01000000".to_string()))
778                .0,
779            "2"
780        );
781    }
782
783    #[test]
784    fn posit8_translation_from_biguint() {
785        assert_eq!(
786            Posit8Translator {}
787                .basic_translate(8, &VariableValue::BigUint(BigUint::from(0b10001000u8)))
788                .0,
789            "-8"
790        );
791        assert_eq!(
792            Posit8Translator {}
793                .basic_translate(8, &VariableValue::BigUint(BigUint::from(0u8)))
794                .0,
795            "0"
796        );
797    }
798
799    #[test]
800    fn posit8_translation_from_string() {
801        assert_eq!(
802            Posit8Translator {}
803                .basic_translate(8, &VariableValue::String("11111111".to_string()))
804                .0,
805            "-0.015625"
806        );
807        assert_eq!(
808            Posit8Translator {}
809                .basic_translate(8, &VariableValue::String("00000011".to_string()))
810                .0,
811            "0.046875"
812        );
813        assert_eq!(
814            Posit8Translator {}
815                .basic_translate(8, &VariableValue::String("10000000".to_string()))
816                .0,
817            "NaN"
818        );
819    }
820
821    #[test]
822    fn posit16_translation_from_biguint() {
823        assert_eq!(
824            Posit16Translator {}
825                .basic_translate(
826                    16,
827                    &VariableValue::BigUint(BigUint::from(0b1010101010001000u16))
828                )
829                .0,
830            "-2.68359375"
831        );
832        assert_eq!(
833            Posit16Translator {}
834                .basic_translate(16, &VariableValue::BigUint(BigUint::from(0u16)))
835                .0,
836            "0"
837        );
838    }
839
840    #[test]
841    fn posit16_translation_from_string() {
842        assert_eq!(
843            Posit16Translator {}
844                .basic_translate(16, &VariableValue::String("1111111111111111".to_string()))
845                .0,
846            "-0.000000003725290298461914"
847        );
848        assert_eq!(
849            Posit16Translator {}
850                .basic_translate(16, &VariableValue::String("0111000000000011".to_string()))
851                .0,
852            "16.046875"
853        );
854        assert_eq!(
855            Posit16Translator {}
856                .basic_translate(16, &VariableValue::String("1000000000000000".to_string()))
857                .0,
858            "NaN"
859        );
860    }
861
862    #[test]
863    fn posit32_translation_from_biguint() {
864        assert_eq!(
865            Posit32Translator {}
866                .basic_translate(
867                    32,
868                    &VariableValue::BigUint(BigUint::from(0b1010101010001000u16))
869                )
870                .0,
871            "0.0000000000000000023056236824262055"
872        );
873        assert_eq!(
874            Posit32Translator {}
875                .basic_translate(32, &VariableValue::BigUint(BigUint::from(0u32)))
876                .0,
877            "0"
878        );
879    }
880
881    #[test]
882    fn posit32_translation_from_string() {
883        assert_eq!(
884            Posit32Translator {}
885                .basic_translate(
886                    32,
887                    &VariableValue::String("10000111000000001111111111111111".to_string())
888                )
889                .0,
890            "-8176.000244140625"
891        );
892        assert_eq!(
893            Posit32Translator {}
894                .basic_translate(
895                    32,
896                    &VariableValue::String("01110000000000111000000000000000".to_string())
897                )
898                .0,
899            "257.75"
900        );
901    }
902
903    #[test]
904    fn quire8_translation_from_biguint() {
905        assert_eq!(
906            PositQuire8Translator {}
907                .basic_translate(
908                    32,
909                    &VariableValue::BigUint(BigUint::from(0b1010101010001000u16))
910                )
911                .0,
912            "10"
913        );
914        assert_eq!(
915            PositQuire8Translator {}
916                .basic_translate(32, &VariableValue::BigUint(BigUint::from(0u16)))
917                .0,
918            "0"
919        );
920    }
921
922    #[test]
923    fn quire8_translation_from_string() {
924        assert_eq!(
925            PositQuire8Translator {}
926                .basic_translate(
927                    32,
928                    &VariableValue::String("10000111000000001111111111111111".to_string())
929                )
930                .0,
931            "-64"
932        );
933        assert_eq!(
934            PositQuire8Translator {}
935                .basic_translate(
936                    32,
937                    &VariableValue::String("01110000000000111000000000000000".to_string())
938                )
939                .0,
940            "64"
941        );
942    }
943
944    #[test]
945    fn quire16_translation_from_biguint() {
946        assert_eq!(
947            PositQuire16Translator {}
948                .basic_translate(128, &VariableValue::BigUint(BigUint::from(0b10101010100010001010101010001000101010101000100010101010100010001010101010001000101010101000100010101010100010001010101010001000u128)))
949                .0,
950            "-268435456"
951        );
952        assert_eq!(
953            PositQuire16Translator {}
954                .basic_translate(128, &VariableValue::BigUint(BigUint::from(7u8)))
955                .0,
956            "0.000000003725290298461914"
957        );
958        assert_eq!(
959            PositQuire16Translator {}
960                .basic_translate(128, &VariableValue::BigUint(BigUint::from(0u8)))
961                .0,
962            "0"
963        );
964    }
965
966    #[test]
967    fn quire16_translation_from_string() {
968        assert_eq!(
969            PositQuire16Translator {}
970                .basic_translate(
971                    128,
972                    &VariableValue::String(
973                        "1000011100000000111111111111111101110000000000111000000000000000"
974                            .to_string()
975                    )
976                )
977                .0,
978            "135"
979        );
980        assert_eq!(
981            PositQuire16Translator {}
982                .basic_translate(
983                    128,
984                    &VariableValue::String("01110000000000111000000000000000".to_string())
985                )
986                .0,
987            "0.000000029802322387695313"
988        );
989    }
990
991    #[test]
992    fn bloat16_translation_from_string() {
993        assert_eq!(
994            BFloat16Translator {}
995                .basic_translate(16, &VariableValue::String("0100100011100011".to_string()))
996                .0,
997            "464896"
998        );
999        assert_eq!(
1000            BFloat16Translator {}
1001                .basic_translate(16, &VariableValue::String("1000000000000000".to_string()))
1002                .0,
1003            "-0"
1004        );
1005        assert_eq!(
1006            BFloat16Translator {}
1007                .basic_translate(16, &VariableValue::String("1111111111111111".to_string()))
1008                .0,
1009            "NaN"
1010        );
1011        assert_eq!(
1012            BFloat16Translator {}
1013                .basic_translate(16, &VariableValue::String("01001z0011100011".to_string()))
1014                .0,
1015            "HIGHIMP"
1016        );
1017        assert_eq!(
1018            BFloat16Translator {}
1019                .basic_translate(16, &VariableValue::String("01001q0011100011".to_string()))
1020                .0,
1021            "UNKNOWN VALUES"
1022        );
1023        assert_eq!(
1024            BFloat16Translator {}
1025                .basic_translate(16, &VariableValue::String("01001-0011100011".to_string()))
1026                .0,
1027            "DON'T CARE"
1028        );
1029        assert_eq!(
1030            BFloat16Translator {}
1031                .basic_translate(16, &VariableValue::String("01001w0011100011".to_string()))
1032                .0,
1033            "UNDEF WEAK"
1034        );
1035        assert_eq!(
1036            BFloat16Translator {}
1037                .basic_translate(16, &VariableValue::String("01001h0011100011".to_string()))
1038                .0,
1039            "WEAK"
1040        );
1041        assert_eq!(
1042            BFloat16Translator {}
1043                .basic_translate(16, &VariableValue::String("01001u0011100011".to_string()))
1044                .0,
1045            "UNDEF"
1046        );
1047    }
1048
1049    #[test]
1050    fn bloat16_translation_from_bigunit() {
1051        assert_eq!(
1052            BFloat16Translator {}
1053                .basic_translate(
1054                    16,
1055                    &VariableValue::BigUint(BigUint::from(0b1010101010001000u16))
1056                )
1057                .0,
1058            "-2.4158453e-13"
1059        );
1060        assert_eq!(
1061            BFloat16Translator {}
1062                .basic_translate(
1063                    16,
1064                    &VariableValue::BigUint(BigUint::from(0b1000000000000000u16))
1065                )
1066                .0,
1067            "-0"
1068        );
1069        assert_eq!(
1070            BFloat16Translator {}
1071                .basic_translate(
1072                    16,
1073                    &VariableValue::BigUint(BigUint::from(0b0000000000000000u16))
1074                )
1075                .0,
1076            "0"
1077        );
1078        assert_eq!(
1079            BFloat16Translator {}
1080                .basic_translate(
1081                    16,
1082                    &VariableValue::BigUint(BigUint::from(0b1111111111111111u16))
1083                )
1084                .0,
1085            "NaN"
1086        );
1087    }
1088
1089    #[test]
1090    fn half_translation_from_biguint() {
1091        assert_eq!(
1092            HalfPrecisionTranslator {}
1093                .basic_translate(
1094                    16,
1095                    &VariableValue::BigUint(BigUint::from(0b1000000000000000u16))
1096                )
1097                .0,
1098            "-0"
1099        );
1100        assert_eq!(
1101            HalfPrecisionTranslator {}
1102                .basic_translate(
1103                    16,
1104                    &VariableValue::BigUint(BigUint::from(0b0000000000000000u16))
1105                )
1106                .0,
1107            "0"
1108        );
1109        assert_eq!(
1110            HalfPrecisionTranslator {}
1111                .basic_translate(
1112                    16,
1113                    &VariableValue::BigUint(BigUint::from(0b1111111111111111u16))
1114                )
1115                .0,
1116            "NaN"
1117        );
1118    }
1119
1120    #[test]
1121    fn half_translation_from_string() {
1122        assert_eq!(
1123            HalfPrecisionTranslator {}
1124                .basic_translate(16, &VariableValue::String("0100100011100011".to_string()))
1125                .0,
1126            "9.7734375"
1127        );
1128        assert_eq!(
1129            HalfPrecisionTranslator {}
1130                .basic_translate(16, &VariableValue::String("1000000000000000".to_string()))
1131                .0,
1132            "-0"
1133        );
1134        assert_eq!(
1135            HalfPrecisionTranslator {}
1136                .basic_translate(16, &VariableValue::String("1111111111111111".to_string()))
1137                .0,
1138            "NaN"
1139        );
1140    }
1141
1142    #[test]
1143    fn single_translation_from_bigunit() {
1144        assert_eq!(
1145            SinglePrecisionTranslator {}
1146                .basic_translate(
1147                    32,
1148                    &VariableValue::BigUint(BigUint::from(0b01010101010001001010101010001000u32))
1149                )
1150                .0,
1151            "1.3514794e13"
1152        );
1153        assert_eq!(
1154            SinglePrecisionTranslator {}
1155                .basic_translate(
1156                    32,
1157                    &VariableValue::BigUint(BigUint::from(0b10000000000000000000000000000000u32))
1158                )
1159                .0,
1160            "-0"
1161        );
1162        assert_eq!(
1163            SinglePrecisionTranslator {}
1164                .basic_translate(
1165                    32,
1166                    &VariableValue::BigUint(BigUint::from(0b00000000000000000000000000000000u32))
1167                )
1168                .0,
1169            "0"
1170        );
1171        assert_eq!(
1172            SinglePrecisionTranslator {}
1173                .basic_translate(
1174                    32,
1175                    &VariableValue::BigUint(BigUint::from(0b11111111111111111111111111111111u32))
1176                )
1177                .0,
1178            "NaN"
1179        );
1180    }
1181
1182    #[test]
1183    fn double_translation_from_bigunit() {
1184        assert_eq!(
1185            DoublePrecisionTranslator {}
1186                .basic_translate(
1187                    64,
1188                    &VariableValue::BigUint(BigUint::from(
1189                        0b0101010101000100101010101000100001010101010001001010101010001000u64
1190                    ))
1191                )
1192                .0,
1193            "5.785860578429741e102"
1194        );
1195        assert_eq!(
1196            DoublePrecisionTranslator {}
1197                .basic_translate(
1198                    64,
1199                    &VariableValue::BigUint(BigUint::from(
1200                        0b1000000000000000000000000000000000000000000000000000000000000000u64
1201                    ))
1202                )
1203                .0,
1204            "-0"
1205        );
1206        assert_eq!(
1207            DoublePrecisionTranslator {}
1208                .basic_translate(
1209                    64,
1210                    &VariableValue::BigUint(BigUint::from(
1211                        0b0000000000000000000000000000000000000000000000000000000000000000u64
1212                    ))
1213                )
1214                .0,
1215            "0"
1216        );
1217        assert_eq!(
1218            DoublePrecisionTranslator {}
1219                .basic_translate(
1220                    64,
1221                    &VariableValue::BigUint(BigUint::from(
1222                        0b1111111111111111111111111111111111111111111111111111111111111111u64
1223                    ))
1224                )
1225                .0,
1226            "NaN"
1227        );
1228    }
1229}