Codebase list libcryptx-perl / d1f0d68
Math::BigInt::LTM _log_int() fix by pjacklam Karel Miko 7 years ago
1 changed file(s) with 58 addition(s) and 56 deletion(s). Raw diff Collapse all Expand all
117117 # based on _log_int() in Math::BigInt::GMP
118118
119119 sub _log_int {
120 my ($c,$x,$base) = @_;
120 my ($c, $x, $base) = @_;
121121
122122 # X == 0 => NaN
123 return if _is_zero($c,$x);
124
125 $base = _new($c,2) unless defined $base;
126 $base = _new($c,$base) unless ref $base;
123 return if _is_zero($c, $x);
124
125 $base = _new($c, 2) unless defined $base;
126 $base = _new($c, $base) unless ref $base;
127127
128128 # BASE 0 or 1 => NaN
129 return if (_is_zero($c, $base) ||
130 _is_one($c, $base));
131
132 my $cmp = _acmp($c,$x,$base); # X == BASE => 1
129 return if _is_zero($c, $base) || _is_one($c, $base);
130
131 # X == 1 => 0 (is exact)
132 if (_is_one($c, $x)) {
133 _set($c, $x, 0);
134 return $x, 1;
135 }
136
137 my $cmp = _acmp($c, $x, $base);
138
139 # X == BASE => 1 (is exact)
133140 if ($cmp == 0) {
134 # return one
135 return (_one($c), 1);
136 }
137 # X < BASE
141 _set($c, $x, 1);
142 return $x, 1;
143 }
144
145 # 1 < X < BASE => 0 (is truncated)
138146 if ($cmp < 0) {
139 return (_zero($c),undef);
140 }
147 _set($c, $x, 0);
148 return $x, 0;
149 }
150
151 my $x_org = _copy($c, $x);
152
153 # Alternative 1:
141154
142155 # Compute a guess for the result based on:
143 # $guess = int ( length_in_base_10(X) / ( log(base) / log(10) ) )
144 my $len = _len($c,$x);
145 my $log = log( _str($c,$base) ) / log(10);
146
147 # calculate now a guess based on the values obtained above:
148 my $x_org = _copy($c,$x);
149
150 # keep the reference to $x, modifying it in place
156 # $guess = int( length_in_base_10(X) / ( log(base) / log(10) ) )
157
158 my $len = _alen($c, $x);
159 my $log = log(_num($c, $base)) / log(10);
160
151161 _set($c, $x, int($len / $log) - 1);
152162
153 my $trial = _pow ($c, _copy($c, $base), $x);
154 my $a = _acmp($c,$trial,$x_org);
155
156 if ($a == 0) {
157 return ($x,1);
158 }
159 elsif ($a > 0) {
160 # too big, shouldn't happen
161 _div($c,$trial,$base); _dec($c, $x);
162 }
163
164 # find the real result by going forward:
165 my $base_mul = _mul($c, _copy($c,$base), $base);
166 my $two = _two($c);
167
168 while (($a = _acmp($c, $trial, $x_org)) < 0) {
169 _mul($c,$trial,$base_mul); _add($c, $x, $two);
170 }
171
172 my $exact = 1;
173 if ($a > 0) {
174 # overstepped the result
175 _dec($c, $x);
176 _div($c,$trial,$base);
177 $a = _acmp($c,$trial,$x_org);
178 if ($a > 0) {
163 my $trial = _pow($c, _copy($c, $base), $x);
164 my $acmp = _acmp($c, $trial, $x_org);
165
166 # Exact result?
167
168 return $x, 1 if $acmp == 0;
169
170 # Too small?
171
172 while ($acmp < 0) {
173 _mul($c, $trial, $base);
174 _inc($c, $x);
175 $acmp = _acmp($c, $trial, $x_org);
176 }
177
178 # Too big?
179
180 while ($acmp > 0) {
181 _div($c, $trial, $base);
179182 _dec($c, $x);
180 }
181 $exact = 0 if $a != 0;
182 }
183
184 return ($x, $exact);
185 }
186
183 $acmp = _acmp($c, $trial, $x_org);
184 }
185
186 return $x, 1 if $acmp == 0; # result is exact
187 return $x, 0; # result is too small
188 }
187189 1;
188190
189191 __END__