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