1use crate::{
2 core::{
3 circuits::boolean::utils::shift_right,
4 expressions::{circuit::ArithmeticCircuitId, field_expr::FieldExpr},
5 global_value::{field_array::FieldArray, value::FieldValue},
6 },
7 traits::*,
8 utils::{field::BaseField, number::Number, used_field::UsedField},
9};
10use ff::Field;
11use std::ops::{Add, Div, Mul, Sub};
12
13pub type ArcisField = BaseField;
14pub type ArcisValue = FieldValue<ArcisField>;
15pub type ArcisArray<const N: usize> = FieldArray<N, ArcisField>;
16
17#[derive(Debug, Clone, Copy)]
19pub struct ArcisFloatValue(pub ArcisValue);
20
21impl ArcisFloatValue {
22 pub const MINUS_PLSB: usize = DOUBLE_PRECISION_MANTISSA;
23 pub fn max_bounds() -> (ArcisField, ArcisField) {
25 (
26 -ArcisField::power_of_two(127),
27 ArcisField::power_of_two(127) - ArcisField::ONE,
28 )
29 }
30 pub fn number_to_f64(a: Number) -> f64 {
31 f64::from(a) / 2.0f64.powi(52)
32 }
33 pub fn number_with_precision_to_f64(a: Number, precision: usize) -> f64 {
34 f64::from(a) / 2.0f64.powi(precision as i32)
35 }
36 pub fn i128_to_f64(a: i128) -> f64 {
37 Self::number_to_f64(a.into())
38 }
39 pub fn i128_to_f32(a: i128) -> f32 {
40 Self::i128_to_f64(a) as f32
41 }
42 pub fn f64_to_i128(a: f64) -> i128 {
43 let value = a.clamp(-(2f64.powi(75)), 2f64.powi(75));
44 (value * 2f64.powi(DOUBLE_PRECISION_MANTISSA as i32)) as i128
45 }
46 pub fn f32_to_i128(a: f32) -> i128 {
47 let value = a.clamp(-(2f32.powi(75)), 2f32.powi(75));
48 (value * 2f32.powi(DOUBLE_PRECISION_MANTISSA as i32)) as i128
49 }
50 pub fn f64_to_number(a: f64) -> Number {
51 let value = a.clamp(-(2f64.powi(75)), 2f64.powi(75));
52 Number::from(value * 2f64.powi(DOUBLE_PRECISION_MANTISSA as i32))
53 }
54 pub fn f32_to_number(a: f32) -> Number {
55 let value = a.clamp(-(2f32.powi(75)), 2f32.powi(75));
56 Number::from(value * 2f32.powi(DOUBLE_PRECISION_MANTISSA as i32))
57 }
58}
59
60impl From<ArcisValue> for ArcisFloatValue {
61 fn from(value: ArcisValue) -> Self {
62 Self(value)
63 }
64}
65
66impl From<ArcisFloatValue> for ArcisValue {
67 fn from(a: ArcisFloatValue) -> ArcisValue {
68 a.0
69 }
70}
71
72impl TryFrom<f64> for ArcisFloatValue {
73 type Error = &'static str;
74
75 fn try_from(value: f64) -> Result<Self, &'static str> {
76 if value < -(2f64.powi(75)) || value >= 2f64.powi(75) {
77 Err("Arcis only supports inputs in the range [-2**75, 2**75)")
78 } else {
79 Ok(ArcisFloatValue(FieldValue::new(FieldExpr::Val(
80 ArcisFloatValue::f64_to_number(value).into(),
81 ))))
82 }
83 }
84}
85
86macro_rules! impl_float_comparison_op {
87 ($op:ident, $opfn:ident) => {
88 impl $op<Self> for ArcisFloatValue {
89 type Output = ArcisValue;
90
91 fn $opfn(self, other: Self) -> Self::Output {
92 ArcisValue::from(self.0.$opfn(other.0))
93 }
94 }
95
96 impl $op<f64> for ArcisFloatValue {
97 type Output = ArcisValue;
98
99 fn $opfn(self, other: f64) -> Self::Output {
100 ArcisValue::from(self.0.$opfn(ArcisFloatValue::try_from(other).unwrap().0))
101 }
102 }
103 };
104}
105
106impl_float_comparison_op!(Equal, eq);
107impl_float_comparison_op!(GreaterThan, gt);
108impl_float_comparison_op!(GreaterEqual, ge);
109
110macro_rules! impl_float_arithmetic_op {
111 ($op:ident, $opfn:ident) => {
112 impl $op<ArcisFloatValue> for ArcisFloatValue {
113 type Output = Self;
114
115 fn $opfn(self, other: Self) -> Self {
116 Self(self.0.$opfn(other.0))
117 }
118 }
119
120 impl $op<f64> for ArcisFloatValue {
121 type Output = ArcisFloatValue;
122
123 fn $opfn(self, other: f64) -> Self::Output {
124 Self(self.0.$opfn(ArcisFloatValue::try_from(other).unwrap().0))
125 }
126 }
127 };
128}
129
130impl_float_arithmetic_op!(Add, add);
131impl_float_arithmetic_op!(Sub, sub);
132
133pub(crate) const DOUBLE_PRECISION_MANTISSA: usize = 52;
134
135impl Mul for ArcisFloatValue {
136 type Output = Self;
137
138 fn mul(self, rhs: Self) -> Self::Output {
139 let prod = self.0 * rhs.0;
140 Self(shift_right(prod, DOUBLE_PRECISION_MANTISSA, true))
141 }
142}
143impl Div for ArcisFloatValue {
144 type Output = Self;
145
146 fn div(self, rhs: ArcisFloatValue) -> Self::Output {
147 Self(ArithmeticCircuitId::Div.apply(vec![self.0, rhs.0])[0])
148 }
149}