1- /*
2- MIT License
3-
4- Copyright (c) 2023 Script3 Ltd. and contributors
5-
6- Permission is hereby granted, free of charge, to any person obtaining a copy
7- of this software and associated documentation files (the "Software"), to deal
8- in the Software without restriction, including without limitation the rights
9- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10- copies of the Software, and to permit persons to whom the Software is
11- furnished to do so, subject to the following conditions:
12-
13- The above copyright notice and this permission notice shall be included in all
14- copies or substantial portions of the Software.
15-
16- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22- SOFTWARE.
23- */
241// Based on the Soroban fixed-point mathematics library
252// Original implementation: https://github.com/script3/soroban-fixed-point-math
263
274use soroban_sdk:: { panic_with_error, Env , I256 } ;
285
29- use crate :: math:: { soroban_fixed_point :: SorobanFixedPoint , SorobanFixedPointError } ;
6+ use crate :: math:: { SorobanFixedPoint , SorobanFixedPointError } ;
307
318/// Performs floor(r / z)
329fn div_floor ( r : i128 , z : i128 ) -> Option < i128 > {
@@ -60,9 +37,17 @@ impl SorobanFixedPoint for i128 {
6037 fn fixed_mul_ceil ( & self , env : & Env , y : & i128 , denominator : & i128 ) -> i128 {
6138 scaled_mul_div_ceil ( self , env, y, denominator)
6239 }
40+
41+ fn checked_fixed_mul_floor ( & self , env : & Env , y : & i128 , denominator : & i128 ) -> Option < i128 > {
42+ checked_scaled_mul_div_floor ( self , env, y, denominator)
43+ }
44+
45+ fn checked_fixed_mul_ceil ( & self , env : & Env , y : & i128 , denominator : & i128 ) -> Option < i128 > {
46+ checked_scaled_mul_div_ceil ( self , env, y, denominator)
47+ }
6348}
6449
65- /// Performs floor(x * y / z)
50+ /// Performs floor(x * y / z), panics on overflow or division by zero
6651fn scaled_mul_div_floor ( x : & i128 , env : & Env , y : & i128 , z : & i128 ) -> i128 {
6752 match x. checked_mul ( * y) {
6853 Some ( r) => div_floor ( r, * z)
@@ -81,7 +66,7 @@ fn scaled_mul_div_floor(x: &i128, env: &Env, y: &i128, z: &i128) -> i128 {
8166 }
8267}
8368
84- /// Performs floor (x * y / z)
69+ /// Performs ceil (x * y / z)
8570fn scaled_mul_div_ceil ( x : & i128 , env : & Env , y : & i128 , z : & i128 ) -> i128 {
8671 match x. checked_mul ( * y) {
8772 Some ( r) => div_ceil ( r, * z)
@@ -99,3 +84,37 @@ fn scaled_mul_div_ceil(x: &i128, env: &Env, y: &i128, z: &i128) -> i128 {
9984 }
10085 }
10186}
87+
88+ /// Checked version of floor(x * y / z)
89+ fn checked_scaled_mul_div_floor ( x : & i128 , env : & Env , y : & i128 , z : & i128 ) -> Option < i128 > {
90+ match x. checked_mul ( * y) {
91+ Some ( r) => div_floor ( r, * z) ,
92+ None => {
93+ // scale to i256 and retry
94+ let res = crate :: math:: i256_fixed_point:: checked_mul_div_floor (
95+ env,
96+ & I256 :: from_i128 ( env, * x) ,
97+ & I256 :: from_i128 ( env, * y) ,
98+ & I256 :: from_i128 ( env, * z) ,
99+ ) ;
100+ res. map ( |r| r. to_i128 ( ) ) ?
101+ }
102+ }
103+ }
104+
105+ /// Checked version of ceil(x * y / z)
106+ fn checked_scaled_mul_div_ceil ( x : & i128 , env : & Env , y : & i128 , z : & i128 ) -> Option < i128 > {
107+ match x. checked_mul ( * y) {
108+ Some ( r) => div_ceil ( r, * z) ,
109+ None => {
110+ // scale to i256 and retry
111+ let res = crate :: math:: i256_fixed_point:: checked_mul_div_ceil (
112+ env,
113+ & I256 :: from_i128 ( env, * x) ,
114+ & I256 :: from_i128 ( env, * y) ,
115+ & I256 :: from_i128 ( env, * z) ,
116+ ) ;
117+ res. map ( |r| r. to_i128 ( ) ) ?
118+ }
119+ }
120+ }
0 commit comments