@@ -7,6 +7,7 @@ use crate::state::State;
77
88pub struct Stack {
99 s : VecDeque < BigDecimal > ,
10+ // Precision when taking a snapshot (not of internal representation).
1011 precision : u64 ,
1112}
1213
@@ -60,20 +61,20 @@ impl Stack {
6061 self . s . push_front ( v) ;
6162 }
6263 Op :: Add => {
63- let [ b , a ] = self . pop ( ) ?;
64+ let [ a , b ] = self . pop ( ) ?;
6465 self . s . push_front ( a + b) ;
6566 }
6667 Op :: Subtract => {
67- let [ b , a ] = self . pop ( ) ?;
68+ let [ a , b ] = self . pop ( ) ?;
6869 self . s . push_front ( a - b) ;
6970 }
7071 Op :: Multiply => {
71- let [ b , a ] = self . pop ( ) ?;
72+ let [ a , b ] = self . pop ( ) ?;
7273 self . s . push_front ( a * b) ;
7374 }
7475 Op :: Divide => {
75- let [ b , a ] = self . check_and_pop ( |stack : & [ BigDecimal ; 2 ] | {
76- if stack[ 0 ] == BigDecimal :: zero ( ) {
76+ let [ a , b ] = self . check_and_pop ( |stack : & [ BigDecimal ; 2 ] | {
77+ if stack[ 1 ] == BigDecimal :: zero ( ) {
7778 Err ( StackError :: InvalidArgument (
7879 "element 1 must be non-zero" . into ( ) ,
7980 ) )
@@ -84,7 +85,7 @@ impl Stack {
8485 self . s . push_front ( a / b) ;
8586 }
8687 Op :: Modulo => {
87- let [ b , a ] = self . pop ( ) ?;
88+ let [ a , b ] = self . pop ( ) ?;
8889 self . s . push_front ( a % b) ;
8990 }
9091 Op :: Sqrt => {
@@ -100,36 +101,40 @@ impl Stack {
100101 self . s . push_front ( a. sqrt ( ) . unwrap ( ) ) ;
101102 }
102103 Op :: Pow => {
103- let [ b, a] = self . check_and_pop ( |stack : & [ BigDecimal ; 2 ] | {
104- if !( stack[ 0 ] . is_integer ( ) && stack[ 0 ] > BigDecimal :: zero ( ) ) {
104+ // This is the only operation that needs to crack open the representation.
105+ // Careful, BigDecimal's scale works not only as the number of digits after
106+ // the dot, it's really a generalized
107+ // int_value . 10^-scale
108+ let [ a, b] = self . prep_and_pop ( |stack : & [ BigDecimal ; 2 ] | {
109+ let [ a, b] = stack;
110+ if !( b. is_integer ( ) && b > & BigDecimal :: zero ( ) && b < & u64:: MAX . into ( ) ) {
105111 return Err ( StackError :: InvalidArgument (
106112 "element 1 must be a positive integer" . into ( ) ,
107113 ) ) ;
108114 }
109- if !stack [ 1 ] . is_integer ( ) {
115+ if !a . is_integer ( ) {
110116 return Err ( StackError :: InvalidArgument (
111117 "element 2 must be an integer" . into ( ) ,
112118 ) ) ;
113119 }
114- let a = stack[ 1 ] . as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
115- let b = stack[ 0 ] . as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
120+ // We know the numbers are integers, but we still need to flush all
121+ // the digits into the bigint where we can express the Pow operation.
122+ let a = a. with_scale ( 0 ) . as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
123+ let b = b. with_scale ( 0 ) . as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
116124 // Arbitrarily cap the number of digits of the result to avoid
117125 // accidental freeze / memory blowup when pressing ^ too many times.
118126 if BigInt :: from ( a. bits ( ) ) * & b > BigInt :: from ( MAX_BIT_COUNT ) {
119127 return Err ( StackError :: InvalidArgument (
120128 "chickening out of creating such a large result" . into ( ) ,
121129 ) ) ;
122130 }
123- Ok ( ( ) )
131+ Ok ( [ a , b ] )
124132 } ) ?;
125- let a = a. as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
126- let b = b. as_bigint_and_scale ( ) . 0 . into_owned ( ) ;
127133 let result = a. pow ( b. to_biguint ( ) . unwrap ( ) ) ;
128134 // Normalization ensures the exponent representation is simplified.
129135 // For instance 10^100 -> (1, -100) after normalization instead of
130136 // (1e100, 0).
131- self . s
132- . push_front ( BigDecimal :: from_bigint ( result, 0 ) . normalized ( ) ) ;
137+ self . s . push_front ( BigDecimal :: from_bigint ( result, 0 ) ) ;
133138 }
134139 Op :: Duplicate => {
135140 let [ a] = self . pop ( ) ?;
@@ -155,7 +160,7 @@ impl Stack {
155160 self . precision = a. to_u64 ( ) . unwrap ( ) ;
156161 }
157162 Op :: Rotate => {
158- let [ b , a ] = self . pop ( ) ?;
163+ let [ a , b ] = self . pop ( ) ?;
159164 self . s . push_front ( b) ;
160165 self . s . push_front ( a) ;
161166 }
@@ -179,25 +184,43 @@ impl Stack {
179184 . collect ( )
180185 }
181186
187+ // Validate a segment of the stack through a user-provided function and return it.
188+ // Note: the elements are returned in the reverse order of the stack, which is the
189+ // natural order for running operations.
182190 fn check_and_pop < const C : usize , F : Fn ( & [ BigDecimal ; C ] ) -> Result < ( ) , StackError > > (
183191 & mut self ,
184192 validator : F ,
185193 ) -> Result < [ BigDecimal ; C ] , StackError > {
194+ self . prep_and_pop ( move |input| {
195+ validator ( input) ?;
196+ Ok ( input. clone ( ) )
197+ } )
198+ }
199+
200+ // Transform a segment of the stack through a user-provided function and return it.
201+ // Note: the elements are returned in the reverse order of the stack, which is the
202+ // natural order for running operations.
203+ fn prep_and_pop < const C : usize , T , F : Fn ( & [ BigDecimal ; C ] ) -> Result < [ T ; C ] , StackError > > (
204+ & mut self ,
205+ validator : F ,
206+ ) -> Result < [ T ; C ] , StackError > {
186207 if self . s . len ( ) < C {
187208 return Err ( StackError :: MissingValue ( C ) ) ;
188209 }
189210 let result = self
190211 . s
191212 . range ( 0 ..C )
213+ . rev ( )
192214 . cloned ( )
193215 . collect :: < Vec < BigDecimal > > ( )
194216 . try_into ( )
195217 . unwrap ( ) ;
196- validator ( & result) ?;
218+ let result = validator ( & result) ?;
197219 self . s . drain ( 0 ..C ) ;
198220 Ok ( result)
199221 }
200222
223+ // Return a segment of the stack in reverse order.
201224 fn pop < const C : usize > ( & mut self ) -> Result < [ BigDecimal ; C ] , StackError > {
202225 self . check_and_pop ( |_| Ok ( ( ) ) )
203226 }
@@ -217,6 +240,8 @@ impl TryFrom<State> for Stack {
217240
218241#[ cfg( test) ]
219242mod tests {
243+ use bigdecimal:: num_bigint:: { self } ;
244+
220245 use super :: * ;
221246
222247 #[ test]
@@ -370,4 +395,18 @@ mod tests {
370395
371396 Ok ( ( ) )
372397 }
398+
399+ #[ test]
400+ fn pow_representation ( ) -> Result < ( ) , StackError > {
401+ let mut s = Stack :: new ( ) ;
402+ s. apply ( Op :: Push ( 10 . into ( ) ) ) ?;
403+ s. apply ( Op :: Push ( 2 . into ( ) ) ) ?;
404+ s. apply ( Op :: Pow ) ?;
405+ let r = s. snapshot ( ) [ 0 ] . clone ( ) ;
406+ let ( bi, s) = r. as_bigint_and_scale ( ) ;
407+
408+ assert_eq ! ( * bi, BigInt :: new( num_bigint:: Sign :: Plus , vec![ 100 ] ) ) ;
409+ assert_eq ! ( s, 0 ) ;
410+ Ok ( ( ) )
411+ }
373412}
0 commit comments