snarkvm_console_types_integers/
arithmetic.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment, I: IntegerType> Neg for Integer<E, I> {
19    type Output = Integer<E, I>;
20
21    /// Returns the `negation` of `self`.
22    #[inline]
23    fn neg(self) -> Self::Output {
24        match I::is_signed() {
25            true => match self.integer.checked_neg() {
26                Some(integer) => Integer::new(integer),
27                None => E::halt(format!("Integer negation failed on: {}", self.integer)),
28            },
29            false => E::halt("Negation of unsigned integers is not supported."),
30        }
31    }
32}
33
34impl<E: Environment, I: IntegerType> AbsChecked for Integer<E, I> {
35    type Output = Integer<E, I>;
36
37    /// Returns the `absolute value` of `self`.
38    #[inline]
39    fn abs_checked(self) -> Self::Output {
40        match I::is_signed() {
41            true => match self.integer.checked_abs() {
42                Some(integer) => Integer::new(integer),
43                None => E::halt(format!("Integer absolute value failed on: {}", self.integer)),
44            },
45            false => self,
46        }
47    }
48}
49
50impl<E: Environment, I: IntegerType> AbsWrapped for Integer<E, I> {
51    type Output = Integer<E, I>;
52
53    /// Returns the `absolute value` of `self`.
54    #[inline]
55    fn abs_wrapped(self) -> Self::Output {
56        match I::is_signed() {
57            true => Integer::new(self.integer.wrapping_abs()),
58            false => self,
59        }
60    }
61}
62
63impl<E: Environment, I: IntegerType> Add<Integer<E, I>> for Integer<E, I> {
64    type Output = Integer<E, I>;
65
66    /// Returns the `sum` of `self` and `other`.
67    #[inline]
68    fn add(self, other: Integer<E, I>) -> Self::Output {
69        match self.integer.checked_add(&other.integer) {
70            Some(integer) => Integer::new(integer),
71            None => E::halt(format!("Integer addition failed on: {self} and {other}")),
72        }
73    }
74}
75
76impl<E: Environment, I: IntegerType> Add<&Integer<E, I>> for Integer<E, I> {
77    type Output = Integer<E, I>;
78
79    /// Returns the `sum` of `self` and `other`.
80    #[inline]
81    fn add(self, other: &Integer<E, I>) -> Self::Output {
82        match self.integer.checked_add(&other.integer) {
83            Some(integer) => Integer::new(integer),
84            None => E::halt(format!("Integer addition failed on: {self} and {other}")),
85        }
86    }
87}
88
89impl<E: Environment, I: IntegerType> AddWrapped<Integer<E, I>> for Integer<E, I> {
90    type Output = Integer<E, I>;
91
92    /// Returns the `sum` of `self` and `other`.
93    #[inline]
94    fn add_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
95        Integer::new(self.integer.wrapping_add(&other.integer))
96    }
97}
98
99impl<E: Environment, I: IntegerType> AddAssign<Integer<E, I>> for Integer<E, I> {
100    /// Adds `other` to `self`.
101    #[inline]
102    fn add_assign(&mut self, other: Integer<E, I>) {
103        match self.integer.checked_add(&other.integer) {
104            Some(integer) => self.integer = integer,
105            None => E::halt(format!("Integer addition failed on: {self} and {other}")),
106        }
107    }
108}
109
110impl<E: Environment, I: IntegerType> AddAssign<&Integer<E, I>> for Integer<E, I> {
111    /// Adds `other` to `self`.
112    #[inline]
113    fn add_assign(&mut self, other: &Integer<E, I>) {
114        match self.integer.checked_add(&other.integer) {
115            Some(integer) => self.integer = integer,
116            None => E::halt(format!("Integer addition failed on: {self} and {other}")),
117        }
118    }
119}
120
121impl<E: Environment, I: IntegerType> Sub<Integer<E, I>> for Integer<E, I> {
122    type Output = Integer<E, I>;
123
124    /// Returns the `difference` of `self` and `other`.
125    #[inline]
126    fn sub(self, other: Integer<E, I>) -> Self::Output {
127        match self.integer.checked_sub(&other.integer) {
128            Some(integer) => Integer::new(integer),
129            None => E::halt(format!("Integer subtraction failed on: {self} and {other}")),
130        }
131    }
132}
133
134impl<E: Environment, I: IntegerType> Sub<&Integer<E, I>> for Integer<E, I> {
135    type Output = Integer<E, I>;
136
137    /// Returns the `difference` of `self` and `other`.
138    #[inline]
139    fn sub(self, other: &Integer<E, I>) -> Self::Output {
140        match self.integer.checked_sub(&other.integer) {
141            Some(integer) => Integer::new(integer),
142            None => E::halt(format!("Integer subtraction failed on: {self} and {other}")),
143        }
144    }
145}
146
147impl<E: Environment, I: IntegerType> SubWrapped<Integer<E, I>> for Integer<E, I> {
148    type Output = Integer<E, I>;
149
150    /// Returns the `difference` of `self` and `other`.
151    #[inline]
152    fn sub_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
153        Integer::new(self.integer.wrapping_sub(&other.integer))
154    }
155}
156
157impl<E: Environment, I: IntegerType> SubAssign<Integer<E, I>> for Integer<E, I> {
158    /// Subtracts `other` from `self`.
159    #[inline]
160    fn sub_assign(&mut self, other: Integer<E, I>) {
161        match self.integer.checked_sub(&other.integer) {
162            Some(integer) => self.integer = integer,
163            None => E::halt(format!("Integer subtraction failed on: {self} and {other}")),
164        }
165    }
166}
167
168impl<E: Environment, I: IntegerType> SubAssign<&Integer<E, I>> for Integer<E, I> {
169    /// Subtracts `other` from `self`.
170    #[inline]
171    fn sub_assign(&mut self, other: &Integer<E, I>) {
172        match self.integer.checked_sub(&other.integer) {
173            Some(integer) => self.integer = integer,
174            None => E::halt(format!("Integer subtraction failed on: {self} and {other}")),
175        }
176    }
177}
178
179impl<E: Environment, I: IntegerType> Mul<Integer<E, I>> for Integer<E, I> {
180    type Output = Integer<E, I>;
181
182    /// Returns the `product` of `self` and `other`.
183    #[inline]
184    fn mul(self, other: Integer<E, I>) -> Self::Output {
185        match self.integer.checked_mul(&other.integer) {
186            Some(integer) => Integer::new(integer),
187            None => E::halt(format!("Integer multiplication failed on: {self} and {other}")),
188        }
189    }
190}
191
192impl<E: Environment, I: IntegerType> Mul<&Integer<E, I>> for Integer<E, I> {
193    type Output = Integer<E, I>;
194
195    /// Returns the `product` of `self` and `other`.
196    #[inline]
197    fn mul(self, other: &Integer<E, I>) -> Self::Output {
198        match self.integer.checked_mul(&other.integer) {
199            Some(integer) => Integer::new(integer),
200            None => E::halt(format!("Integer multiplication failed on: {self} and {other}")),
201        }
202    }
203}
204
205impl<E: Environment, I: IntegerType> MulWrapped<Integer<E, I>> for Integer<E, I> {
206    type Output = Integer<E, I>;
207
208    /// Returns the `product` of `self` and `other`.
209    #[inline]
210    fn mul_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
211        Integer::new(self.integer.wrapping_mul(&other.integer))
212    }
213}
214
215impl<E: Environment, I: IntegerType> MulAssign<Integer<E, I>> for Integer<E, I> {
216    /// Multiplies `self` by `other`.
217    #[inline]
218    fn mul_assign(&mut self, other: Integer<E, I>) {
219        match self.integer.checked_mul(&other.integer) {
220            Some(integer) => self.integer = integer,
221            None => E::halt(format!("Integer multiplication failed on: {self} and {other}")),
222        }
223    }
224}
225
226impl<E: Environment, I: IntegerType> MulAssign<&Integer<E, I>> for Integer<E, I> {
227    /// Multiplies `self` by `other`.
228    #[inline]
229    fn mul_assign(&mut self, other: &Integer<E, I>) {
230        match self.integer.checked_mul(&other.integer) {
231            Some(integer) => self.integer = integer,
232            None => E::halt(format!("Integer multiplication failed on: {self} and {other}")),
233        }
234    }
235}
236
237impl<E: Environment, I: IntegerType> Div<Integer<E, I>> for Integer<E, I> {
238    type Output = Integer<E, I>;
239
240    /// Returns the `quotient` of `self` and `other`.
241    #[inline]
242    fn div(self, other: Integer<E, I>) -> Self::Output {
243        match self.integer.checked_div(&other.integer) {
244            Some(integer) => Integer::new(integer),
245            None => E::halt(format!("Integer division failed on: {self} and {other}")),
246        }
247    }
248}
249
250impl<E: Environment, I: IntegerType> Div<&Integer<E, I>> for Integer<E, I> {
251    type Output = Integer<E, I>;
252
253    /// Returns the `quotient` of `self` and `other`.
254    #[inline]
255    fn div(self, other: &Integer<E, I>) -> Self::Output {
256        match self.integer.checked_div(&other.integer) {
257            Some(integer) => Integer::new(integer),
258            None => E::halt(format!("Integer division failed on: {self} and {other}")),
259        }
260    }
261}
262
263impl<E: Environment, I: IntegerType> DivWrapped<Integer<E, I>> for Integer<E, I> {
264    type Output = Integer<E, I>;
265
266    /// Returns the `quotient` of `self` and `other`.
267    #[inline]
268    fn div_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
269        match other.is_zero() {
270            true => E::halt(format!("Integer division by zero: {self} / {other}")),
271            false => Integer::new(self.integer.wrapping_div(&other.integer)),
272        }
273    }
274}
275
276impl<E: Environment, I: IntegerType> DivAssign<Integer<E, I>> for Integer<E, I> {
277    /// Divides `self` by `other`.
278    #[inline]
279    fn div_assign(&mut self, other: Integer<E, I>) {
280        match self.integer.checked_div(&other.integer) {
281            Some(integer) => self.integer = integer,
282            None => E::halt(format!("Integer division failed on: {self} and {other}")),
283        }
284    }
285}
286
287impl<E: Environment, I: IntegerType> DivAssign<&Integer<E, I>> for Integer<E, I> {
288    /// Divides `self` by `other`.
289    #[inline]
290    fn div_assign(&mut self, other: &Integer<E, I>) {
291        match self.integer.checked_div(&other.integer) {
292            Some(integer) => self.integer = integer,
293            None => E::halt(format!("Integer division failed on: {self} and {other}")),
294        }
295    }
296}
297
298impl<E: Environment, I: IntegerType> Modulo<Integer<E, I>> for Integer<E, I> {
299    type Output = Integer<E, I>;
300
301    /// Returns the result of taking the modulus of `self` with respect to `other`.
302    #[inline]
303    fn modulo(&self, other: &Integer<E, I>) -> Self {
304        match I::is_signed() {
305            true => E::halt("Taking the modulus of signed integers is not supported"),
306            false => match other.is_zero() {
307                true => E::halt(format!("Integer modulus by zero: {self} % {other}")),
308                false => Integer::new(self.integer.modulo(&other.integer)),
309            },
310        }
311    }
312}
313
314impl<E: Environment, I: IntegerType> Rem<Integer<E, I>> for Integer<E, I> {
315    type Output = Integer<E, I>;
316
317    /// Returns the `remainder` of `self` divided by `other`.
318    #[inline]
319    fn rem(self, other: Integer<E, I>) -> Self {
320        match self.integer.checked_rem(&other.integer) {
321            Some(integer) => Integer::new(integer),
322            None => E::halt(format!("Integer remainder failed on: {self} and {other}")),
323        }
324    }
325}
326
327impl<E: Environment, I: IntegerType> Rem<&Integer<E, I>> for Integer<E, I> {
328    type Output = Integer<E, I>;
329
330    /// Returns the `remainder` of `self` divided by `other`.
331    #[inline]
332    fn rem(self, other: &Integer<E, I>) -> Self {
333        match self.integer.checked_rem(&other.integer) {
334            Some(integer) => Integer::new(integer),
335            None => E::halt(format!("Integer remainder failed on: {self} and {other}")),
336        }
337    }
338}
339
340impl<E: Environment, I: IntegerType> RemWrapped<Integer<E, I>> for Integer<E, I> {
341    type Output = Integer<E, I>;
342
343    /// Returns the `remainder` of `self` divided by `other`.
344    #[inline]
345    fn rem_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
346        match other.is_zero() {
347            true => E::halt(format!("Integer remainder by zero: {self} % {other}")),
348            false => Integer::new(self.integer.wrapping_rem(&other.integer)),
349        }
350    }
351}
352
353impl<E: Environment, I: IntegerType> RemAssign<Integer<E, I>> for Integer<E, I> {
354    /// Returns the `remainder` of `self` divided by `other`.
355    #[inline]
356    fn rem_assign(&mut self, other: Integer<E, I>) {
357        match self.integer.checked_rem(&other.integer) {
358            Some(integer) => self.integer = integer,
359            None => E::halt(format!("Integer remainder failed on: {self} and {other}")),
360        }
361    }
362}
363
364impl<E: Environment, I: IntegerType> RemAssign<&Integer<E, I>> for Integer<E, I> {
365    /// Returns the `remainder` of `self` divided by `other`.
366    #[inline]
367    fn rem_assign(&mut self, other: &Integer<E, I>) {
368        match self.integer.checked_rem(&other.integer) {
369            Some(integer) => self.integer = integer,
370            None => E::halt(format!("Integer remainder failed on: {self} and {other}")),
371        }
372    }
373}
374
375impl<E: Environment, I: IntegerType, M: Magnitude> Pow<Integer<E, M>> for Integer<E, I> {
376    type Output = Integer<E, I>;
377
378    /// Returns the `power` of `self` to the power of `other`.
379    #[inline]
380    fn pow(self, other: Integer<E, M>) -> Self::Output {
381        match self.integer.checked_pow(&other.integer.to_u32().unwrap()) {
382            // Unwrap is safe as we only cast up.
383            Some(integer) => Integer::new(integer),
384            None => E::halt(format!("Integer power failed on: {self} and {other}")),
385        }
386    }
387}
388
389impl<E: Environment, I: IntegerType, M: Magnitude> Pow<&Integer<E, M>> for Integer<E, I> {
390    type Output = Integer<E, I>;
391
392    /// Returns the `power` of `self` to the power of `other`.
393    #[inline]
394    fn pow(self, other: &Integer<E, M>) -> Self::Output {
395        match self.integer.checked_pow(&other.integer.to_u32().unwrap()) {
396            // Unwrap is safe as we only cast up.
397            Some(integer) => Integer::new(integer),
398            None => E::halt(format!("Integer power failed on: {self} and {other}")),
399        }
400    }
401}
402
403impl<E: Environment, I: IntegerType, M: Magnitude> PowWrapped<Integer<E, M>> for Integer<E, I> {
404    type Output = Integer<E, I>;
405
406    /// Returns the `power` of `self` to the power of `other`.
407    #[inline]
408    fn pow_wrapped(&self, other: &Integer<E, M>) -> Self::Output {
409        Integer::new(self.integer.wrapping_pow(&other.integer.to_u32().unwrap()))
410    }
411}
412
413impl<E: Environment, I: IntegerType> Square for Integer<E, I> {
414    type Output = Integer<E, I>;
415
416    /// Returns the `square` of `self`.
417    #[inline]
418    fn square(&self) -> Self::Output {
419        match self.integer.checked_mul(&self.integer) {
420            Some(integer) => Integer::new(integer),
421            None => E::halt(format!("Integer square failed on: {}", self.integer)),
422        }
423    }
424}