/[dtapublic]/to_be_filed/webprojs/php_libraries/php_lib_ceqswdev_com/int_string_arithmetic.inc
ViewVC logotype

Contents of /to_be_filed/webprojs/php_libraries/php_lib_ceqswdev_com/int_string_arithmetic.inc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (show annotations) (download)
Sat Oct 8 23:35:33 2016 UTC (8 years, 1 month ago) by dashley
File size: 47430 byte(s)
Initial commit.
1 <?php
2 //********************************************************************************
3 //Copyright (C) 2007 David T. Ashley
4 //********************************************************************************
5 //This program or source file is free software; you can redistribute it and/or
6 //modify it under the terms of the GNU Lesser General Public License as published
7 //by the Free Software Foundation; either version 2 of the License, or (at your
8 //option) any later version.
9 //
10 //This program or source file is distributed in the hope that it will
11 //be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 //GNU General Public License for more details.
14 //
15 //You may have received a copy of the GNU Lesser General Public License
16 //along with this program; if not, write to the Free Software
17 //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //********************************************************************************
19 //This file implements arithmetic functions on integers (typically large
20 //integers) represented as string. These functions are used as a layer above
21 //the bcmath functions, in case this set of web pages must be implemented on
22 //a version of PHP without bcmath compiled in. In this event, the functions
23 //in this file can be replaced with (slower) PHP functions that perform
24 //the arithmetic on strings directly in PHP. As most of the algorithms on this
25 //set of web pages are O(log N) this _should_ work, but it hasn't been
26 //evaluated for speed.
27 //--------------------------------------------------------------------------------
28 //Notes on canonical form: for use with the numerical functions in this
29 //library, the following conventions apply:
30 // a)Zero has one representation, "0".
31 // b)On non-zero numbers, no leading 0's are allowed.
32 // c)Positive numbers have no leading "+", but negative numbers have a
33 // leading "-".
34 // d)No commas, spaces, or extraneous characters are allowed.
35 // e)The string "INAN" is allowed to indicate that the integer is not a
36 // number. Combining "INAN" with any other number in any other
37 // operation results in "INAN".
38 //
39 //The notes above apply only to the form used for calculation. For presentation
40 //in human-readable form, commas are allowed, and functions are provided to
41 //convert back and forth.
42 //--------------------------------------------------------------------------------
43 //Notes on the "scale" parameter to the bcmath functions ... this is provided on
44 //all calls that accept it in order to override the default value set via
45 //the bcscale() function. Although it should have no effect with natural numbers,
46 //it is provided to provide a more consistent environment and to head off
47 //bugs.
48 //--------------------------------------------------------------------------------
49 require_once("strfunc.inc");
50 //
51 //--------------------------------------------------------------------------------
52 //Result codes that may be returned from functions. These are integers designed
53 //to be masked. Since all known PHP implementations use 32-bit or larger
54 //integers, at least 31 bits are available.
55 define("ISARITH_RC_UPERROR", 0x00000001);
56 //An unidentified parse error occurred.
57 define("ISARITH_RC_EMPTY_STRING", 0x00000002);
58 //A request was made to parse the empty string.
59 define("ISARITH_RC_ICHAR", 0x00000004);
60 //Illegal character(s) other than space or tab were encountered as part of
61 //the parse.
62 define("ISARITH_RC_GAP", 0x00000008);
63 //The string to be parsed contained space or tab gaps.
64 define("ISARITH_RC_BADLIMIT", 0x00000010);
65 //The limits (min, max) passed in were bad or not parseable.
66 define("ISARITH_RC_NOTWHOLENUM", 0x00000020);
67 //The number supplied is not an integer (the mantissa and exponent
68 //create a number with a fractional part).
69 define("ISARITH_RC_IINAN", 0x00000040);
70 //INAN was encountered during the parse, while the parse parameters
71 //indicated that INAN is not allowed.
72 define("ISARITH_RC_2SMALL", 0x00000080);
73 //The value as parsed was smaller than allowed.
74 define("ISARITH_RC_2LARGE", 0x00000100);
75 //The value as parsed was larger than allowed.
76 define("ISARITH_RC_SIGNPARSE", 0x00000200);
77 //Multiple or conflicting mantissa signs were allowed.
78 define("ISARITH_RC_DPPARSE", 0x00000400);
79 //Multiple decimal points were found.
80 define("ISARITH_RC_EXPMPARSE", 0x00000800);
81 //Multiple exponent markers (e or E) were found.
82 define("ISARITH_RC_EMSGN", 0x00001000);
83 //Multiple or conflicting exponent signs were found
84 //--------------------------------------------------------------------------------
85 //Codes to specify behavior when non-integers are encountered.
86 define("ISARITH_NIB_INTEGERSONLY", 0);
87 //Numbers with fractional parts simply aren't allowed. Refuse to do the
88 //conversion and return ISARITH_RC_NOTWHOLENUM.
89 define("ISARITH_NIB_ROUNDNEAREST", 1);
90 //Round to the nearest integer with no exceptions. Values that are halfway
91 //are rounded to the integer of larger magnitude.
92 // 3.1 --> 3
93 // -3.1 --> -3
94 // 2.9 --> 3
95 // -2.9 --> -3
96 // 3.5 --> 4
97 // -3.5 --> -4
98 define("ISARITH_NIB_ROUNDLESSER", 2);
99 //Round to the lesser integer, with "lesser" being strictly defined as
100 //more to the left on the number line.
101 // 3.1 --> 3
102 // -3.1 --> -4
103 // 2.9 --> 2
104 // -2.9 --> -3
105 // 3.5 --> 3
106 // -3.5 --> -4
107 define("ISARITH_NIB_ROUNDGREATER", 3);
108 //Round to the greater integer, with "greater" being strictly defined as
109 //more to the right on the number line.
110 // 3.1 --> 4
111 // -3.1 --> -3
112 // 2.9 --> 3
113 // -2.9 --> -2
114 // 3.5 --> 4
115 // -3.5 --> -3
116 define("ISARITH_NIB_ROUNDLESSERMAG", 4);
117 //Round to the integer of lesser magnitude.
118 // 3.1 --> 3
119 // -3.1 --> -3
120 // 2.9 --> 2
121 // -2.9 --> -2
122 // 3.5 --> 3
123 // -3.5 --> -3
124 define("ISARITH_NIB_ROUNDGREATERMAG", 5);
125 //Round to the integer of greater magnitude.
126 // 3.1 --> 4
127 // -3.1 --> -4
128 // 2.9 --> 3
129 // -2.9 --> -3
130 // 3.5 --> 4
131 // -3.5 --> -4
132 //--------------------------------------------------------------------------------
133 //--------------------------------------------------------------------------------
134 //---- S T A T I C -------------------------------------------------------------
135 //--------------------------------------------------------------------------------
136 //--------------------------------------------------------------------------------
137 //Trims the leading 0's from a string representing a signed or unsigned
138 //integer. The string may have a sign, but may have no spaces or commas.
139 //
140 //If final result is "-0", changed to "0".
141 //
142 function ISARITH_trim_leading_zeros($arg)
143 {
144 //Be sure the argument is a string.
145 $arg = (string)$arg;
146
147 if (strlen($arg) != 0)
148 {
149 if (SubStr($arg, 0, 1) == "-")
150 {
151 //Argument has a minus sign.
152 while(
153 (strlen($arg) >= 3)
154 &&
155 (SubStr($arg, 1, 1) == "0")
156 )
157 {
158 $arg = "-" . SubStr($arg, 2);
159 }
160
161 if (strcmp("-0", $arg) == 0)
162 {
163 $arg = "0";
164 }
165 }
166 else
167 {
168 //Argument has no minus sign.
169 while(
170 (strlen($arg) >= 2)
171 &&
172 (SubStr($arg, 0, 1) == "0")
173 )
174 {
175 $arg = SubStr($arg, 1);
176 }
177 }
178
179 return($arg);
180 }
181 else
182 {
183 //Empty string?
184 return($arg);
185 }
186 }
187 //
188 //--------------------------------------------------------------------------------
189 //Passed an integer representing the bit mask of error codes from a function
190 //in this module, returns an array of symbolic tags indicating the
191 //codes. If no tags, FALSE is returned.
192 //
193 function ISARITH_integer_to_result_code_array($i_in)
194 {
195 if (!is_int($i_in))
196 return(FALSE);
197 else if ($i_in == 0)
198 return(FALSE);
199 else
200 {
201 if ($i_in & ISARITH_RC_UPERROR)
202 $rv[] = "ISARITH_RC_UPERROR";
203 if ($i_in & ISARITH_RC_EMPTY_STRING)
204 $rv[] = "ISARITH_RC_EMPTY_STRING";
205 if ($i_in & ISARITH_RC_ICHAR)
206 $rv[] = "ISARITH_RC_ICHAR";
207 if ($i_in & ISARITH_RC_GAP)
208 $rv[] = "ISARITH_RC_GAP";
209 if ($i_in & ISARITH_RC_BADLIMIT)
210 $rv[] = "ISARITH_RC_BADLIMIT";
211 if ($i_in & ISARITH_RC_NOTWHOLENUM)
212 $rv[] = "ISARITH_RC_NOTWHOLENUM";
213 if ($i_in & ISARITH_RC_IINAN)
214 $rv[] = "ISARITH_RC_IINAN";
215 if ($i_in & ISARITH_RC_2SMALL)
216 $rv[] = "ISARITH_RC_2SMALL";
217 if ($i_in & ISARITH_RC_2LARGE)
218 $rv[] = "ISARITH_RC_2LARGE";
219 if ($i_in & ISARITH_RC_SIGNPARSE)
220 $rv[] = "ISARITH_RC_SIGNPARSE";
221 if ($i_in & ISARITH_RC_DPPARSE)
222 $rv[] = "ISARITH_RC_DPPARSE";
223 if ($i_in & ISARITH_RC_EXPMPARSE)
224 $rv[] = "ISARITH_RC_EXPMPARSE";
225 if ($i_in & ISARITH_RC_EMSGN)
226 $rv[] = "ISARITH_RC_EMSGN";
227
228 if (!isset($rv))
229 $rv = FALSE;
230
231 return($rv);
232 }
233 }
234 //
235 //--------------------------------------------------------------------------------
236 //Forms a decimal number based on the predecimal and postdecimal parts, which
237 //may have had leading and trailing zeros (respectively) removed.
238 //
239 function ISARITH_form_decimal_number($pre_d, $post_d)
240 {
241 if (! strlen($pre_d) && ! strlen($post_d))
242 {
243 //Both strings evaluated to 0's that could be trimmed, 0.0
244 //is the right replacement.
245 $rv = "0.0";
246 }
247 else if (! strlen($pre_d) && strlen($post_d))
248 {
249 //The pre-decimal point value is the empty string, but the
250 //post isn't. 0.Y is the right answer.
251 $rv = "0." . $post_d;
252 }
253 else if (strlen($pre_d) && ! strlen($post_d))
254 {
255 //The post-decimal point value is the empty string, but the
256 //pre isn't. X is the right answer.
257 $rv = $pre_d;
258 }
259 else
260 {
261 //Both are non-empty.
262 $rv = $pre_d . "." . $post_d;
263 }
264
265 return($rv);
266
267 }
268 //
269 //--------------------------------------------------------------------------------
270 //Assigns an arbitrarily long integer from a string. The string is converted
271 //to a simple integer, if possible.
272 //
273 //There are no limits on this function, so it would be possible to cause an
274 //out of memory or other condition by passing in an argument with an exponent
275 //of large absolute value. This function should be reserved for contexts
276 //where user input isn't the source or where it has already been sanitized.
277 //
278 //This function will accept strings to parse in a more relaxed format
279 //than canonical form (it parses things into canonical form). The
280 //specific relaxations are:
281 // a)A unary "+" is allowed, even on "0".
282 // b)Unary "-" is allowed even on "0".
283 // c)Commas are allowed, and need not be properly placed. Commas may occur
284 // even in exponents.
285 //
286 //The input string must be sanitized of spaces and tabs, even leading and trailing
287 //ones. The responsibility of removing these was deliberately pushed off onto the
288 //caller.
289 //
290 //Allowable formats are:
291 // a)Integer format (i.e. "25", "-2,352", "+325", etc.).
292 // b)Scientific notation, i.e. "3.12451234e+23".
293 // c)Optionally, "INAN".
294 //
295 function ISARITH_int_parse_and_separate
296 (
297 $in_i2parse,
298 //The string to parse. As mentioned above, all characters not to be
299 //considered, including leading and trailing blanks and tabs. The design
300 //decision to push this off on the caller was deliberate, as it gives the
301 //caller more latitude to decide what is allowed and not.
302 $in_inan_allowed,
303 //TRUE if INAN is allowed as an input string, or FALSE otherwise.
304 $in_debug,
305 //Flag, per the rules for PHP Boolean interpretation, that indicates whether to
306 //provide debug information per the $debug_out variable.
307 &$out_parse_errs,
308 //An integer reflecting a bitmask of errors (or lack thereof) encountered during
309 //the parse. Zero is the only value which will result in the output values being
310 //all usable. The output values should not be used (values are undefined) if
311 //parse errors were encountered.
312 &$out_is_inan,
313 //TRUE if the value was parsed as INAN, FALSE otherwise.
314 &$out_mant_sign,
315 //The sign character of the mantissa. This will be either "" (no sign specified),
316 //"-" (minus sign specified), or "+" (plus sign specified).
317 &$out_mant_pre_dec,
318 //The mantissa, with commas removed, before the decimal point. If no decimal
319 //point is specified, this would contain the only digits. If no digits
320 //appear before the decimal point, this may be "". All leading 0's are
321 //removed, so if a number such as "0.9" or "0.0" is specified, this may be "".
322 &$out_mant_post_dec,
323 //The mantissa, with commas removed, after the decimal point. All trailing
324 //0's are removed, possibly resulting in "".
325 &$out_exp_sign,
326 //The sign of the exponent, "", "-", or "+".
327 &$out_exp_digits,
328 //The digits of the exponent, with leading 0's removed. No exponent specified
329 //or a number such as "3.14e+00" will result in an empty string here.
330 &$out_display_value_scimatch,
331 //If the integer to parse contained errors, the suggested display value to allow the user
332 //to correct them. If the integer to parse contained no errors, the suggested display
333 //value. With this string, the user's choice of scientific notation or not is matched in the
334 //output. Unlike other fields, if there were errors encountered, this will not be
335 //FALSE (it will always be a string).
336 &$out_debug
337 //If $debug_in is TRUE, this will be populated with an array of strings containing
338 //debug information, otherwise this variable will be FALSE.
339 )
340 {
341 //Assign initial values. This sets the type as well.
342 $out_parse_errors = 0;
343 $out_is_inan = FALSE;
344 $out_mant_sign = "";
345 $out_mant_pre_dec = "";
346 $out_mant_post_dec = "";
347 $out_exp_sign = "";
348 $out_exp_digits = "";
349 $out_display_value_scimatch = "";
350
351 //Set up for debug information.
352 if ($in_debug)
353 {
354 $debug_separator = "- - - - - - - - - - - - - - - - - - - - - - - - - - -";
355 $out_debug[] = $debug_separator;
356 $out_debug[] = "ISARITH_assign_from_string_nolimit() Debug Information";
357 $out_debug[] = $debug_separator;
358 }
359 else
360 {
361 $out_debug = FALSE;
362 }
363
364 //Guard against empty string.
365 $in_i2parse = (string)$in_i2parse;
366 if (strlen($in_i2parse) == 0)
367 {
368 if ($in_debug)
369 {
370 $out_debug[] = "(Line " . __LINE__ . ") Empty string. Returning.";
371 $out_debug[] = $debug_separator;
372 }
373
374 $out_display_value_scimatch = "";
375 $out_parse_errs = ISARITH_RC_EMPTY_STRING;
376 return;
377 }
378
379 //Handle the "INAN" case.
380 if (strcmp($in_i2parse, "INAN") == 0)
381 {
382 if ($in_inan_allowed)
383 {
384 //INAN is allowed, and we have it. Return INAN.
385 if ($in_debug)
386 {
387 $out_debug[] = "(Line " . __LINE__ . ") INAN found and allowed. Returning.";
388 $out_debug[] = $debug_separator;
389 }
390
391 $out_is_inan = TRUE;
392 return;
393 }
394 else
395 {
396 //INAN is not allowed, but we have it. This is an error.
397 if ($in_debug)
398 {
399 $out_debug[] = "(Line " . __LINE__ . ") INAN found and not allowed. Returning.";
400 $out_debug[] = $debug_separator;
401 }
402
403 $out_parse_errs = ISARITH_RC_IINAN;
404 return;
405 }
406 }
407
408 //Guard against invalid characters that are strongly disallowed
409 //(characters even more illegal than spaces or tabs).
410 if (! STRFUNC_is_char_subset($in_i2parse, " \t+-.,eE0123456789"))
411 {
412 if ($in_debug)
413 {
414 $out_debug[] = "(Line " . __LINE__ . ") Illegal character (more extreme than space or tab) found. Returning.";
415 $out_debug[] = $debug_separator;
416 }
417
418 $out_display_value_scimatch = STRFUNC_force_into_subset($in_i2parse, " \t+-.,eE0123456789");
419 $out_parse_errs = ISARITH_RC_ICHAR;
420 return;
421 }
422
423 //Guard against space/tab gaps, which are not allowed.
424 if (! STRFUNC_is_char_subset($in_i2parse, "+-.,eE0123456789"))
425 {
426 if ($in_debug)
427 {
428 $out_debug[] = "(Line " . __LINE__ . ") Space or tab gaps found. Returning.";
429 $out_debug[] = $debug_separator;
430 }
431
432 $out_display_value_scimatch = STRFUNC_force_into_subset($in_i2parse, "+-.,eE0123456789");
433 $out_parse_errs = ISARITH_RC_GAP;
434 return;
435 }
436
437 //Trim any commas from the string. These are by and large ignored.
438 $in_i2parse = STRFUNC_force_into_subset($in_i2parse, "+-.eE0123456789");
439
440 //If we created an empty string, this is a gross
441 //parse error.
442 if (strlen($in_i2parse) == 0)
443 {
444 if ($in_debug)
445 {
446 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error (empty string as intermediate result). Returning.";
447 $out_debug[] = $debug_separator;
448 }
449
450 $out_display_value_scimatch = "";
451 $out_parse_errs = ISARITH_RC_UPERROR;
452 return;
453 }
454
455 //Strip off any leading "-" and "+" signs of the mantissa.
456 $out_mant_sign = "";
457 while
458 (
459 (strlen($in_i2parse) != 0)
460 &&
461 (
462 (SubStr($in_i2parse, 0, 1) == "-")
463 ||
464 (SubStr($in_i2parse, 0, 1) == "+")
465 )
466 )
467 {
468 if (SubStr($in_i2parse, 0, 1) == "-")
469 {
470 if (strlen($out_mant_sign))
471 {
472 //We are finding a second sign character. Not allowed.
473 if ($in_debug)
474 {
475 $out_debug[] = "(Line " . __LINE__ . ") Second sign character found (illegal). Returning.";
476 $out_debug[] = $debug_separator;
477 }
478
479 $out_display_value_scimatch = $in_i2parse;
480 $out_parse_errs = ISARITH_RC_SIGNPARSE;
481 return;
482 }
483 else
484 {
485 //Found a first minus sign. Record it.
486 if ($in_debug)
487 {
488 $out_debug[] = "(Line " . __LINE__ . ") Found a single minus sign (legal).";
489 }
490
491 $out_mant_sign = "-";
492 }
493 }
494 else if (SubStr($in_i2parse, 0, 1) == "+")
495 {
496 if (strlen($out_mant_sign))
497 {
498 //We are finding a second sign character. Not allowed.
499 if ($in_debug)
500 {
501 $out_debug[] = "(Line " . __LINE__ . ") Second sign character found (illegal). Returning.";
502 $out_debug[] = $debug_separator;
503 }
504
505 $out_display_value_scimatch = $in_i2parse;
506 $out_parse_errs = ISARITH_RC_SIGNPARSE;
507 return;
508 }
509 else
510 {
511 //Found a plus sign. Record it.
512 if ($in_debug)
513 {
514 $out_debug[] = "(Line " . __LINE__ . ") Plus sign found (legal).";
515 }
516
517 $out_mant_sign = "+";
518 }
519 }
520
521 //Strip the character.
522 $in_i2parse = SubStr($in_i2parse, 1);
523 } //End while()
524
525 //If we created an empty string, this is a gross
526 //parse error.
527 if (strlen($in_i2parse) == 0)
528 {
529 if ($in_debug)
530 {
531 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error (empty string as intermediate result). Returning.";
532 $out_debug[] = $debug_separator;
533 }
534
535 $out_display_value_scimatch = "";
536 $out_parse_errs = ISARITH_RC_UPERROR;
537 return;
538 }
539
540 //Debug info.
541 if ($in_debug)
542 {
543 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of mantissa sign is \"" .
544 $in_i2parse . "\".";
545 }
546
547 //The next item has to be a decimal point or a digit, otherwise
548 //the mantissa is effectively missing.
549 if (! STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), ".0123456789"))
550 {
551 if ($in_debug)
552 {
553 $debug_out[] = "(Line " . __LINE__ . ") Decimal point or digit not found when starting to parse mantissa. Returning.";
554 }
555
556 $out_display_value_scimatch = $out_mant_sign . $in_i2parse;
557 $out_parse_errs = ISARITH_RC_UPERROR;
558 return;
559 }
560
561 //Remove the digits, if any before the decimal point, if any.
562 while (
563 (strlen($in_i2parse))
564 &&
565 (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
566 )
567 {
568 $out_mant_pre_dec .= SubStr($in_i2parse, 0, 1);
569 $in_i2parse = SubStr($in_i2parse, 1);
570 }
571
572 //Debug info.
573 if ($in_debug)
574 {
575 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of mantissa pre-decimal digits is \"" .
576 $in_i2parse . "\".";
577 }
578
579 //Remove any leading 0's from the string. This may result in "".
580 while
581 (
582 (strlen($out_mant_pre_dec))
583 &&
584 (SubStr($out_mant_pre_dec, 0, 1) == "0")
585 )
586 {
587 $out_mant_pre_dec = SubStr($out_mant_pre_dec, 1);
588 }
589
590 //Debug info.
591 if ($in_debug)
592 {
593 $out_debug[] = "(Line " . __LINE__ . ") out_mant_pre_dec after removal of leading 0's is \"" .
594 $out_mant_pre_dec . "\".";
595 }
596
597 //If we have an empty string, this is a permissible exit point. This would be an integer with
598 //no frills.
599 if (strlen($in_i2parse) == 0)
600 {
601 if ($in_debug)
602 {
603 $out_debug[] = "(Line " . __LINE__ . ") Plain integer detected.";
604 $out_debug[] = $debug_separator;
605 }
606
607 $out_display_value_scimatch = $out_mant_sign . $out_mant_pre_dec;
608 return;
609 }
610
611 //Remove the decimal point, if any.
612 if (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "."))
613 {
614 $in_i2parse = SubStr($in_i2parse, 1);
615 }
616
617 //Debug info.
618 if ($in_debug)
619 {
620 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of decimal point is \"" .
621 $in_i2parse . "\".";
622 }
623
624 //Remove the digits, if any, after the decimal point.
625 while (
626 (strlen($in_i2parse))
627 &&
628 (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
629 )
630 {
631 $out_mant_post_dec .= SubStr($in_i2parse, 0, 1);
632 $in_i2parse = SubStr($in_i2parse, 1);
633 }
634
635 //Debug info.
636 if ($in_debug)
637 {
638 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of mantissa post-decimal digits is \"" .
639 $in_i2parse . "\".";
640 }
641
642 //Remove any trailing 0's from the string. This may result in "".
643 while
644 (
645 (strlen($out_mant_post_dec))
646 &&
647 (SubStr($out_mant_post_dec, strlen($out_mant_post_dec) - 1, 1) == "0")
648 )
649 {
650 $out_mant_post_dec = SubStr($out_mant_post_dec, 0, strlen($out_mant_post_dec) - 1);
651 }
652
653 //Debug info.
654 if ($in_debug)
655 {
656 $out_debug[] = "(Line " . __LINE__ . ") out_mant_post_dec after removal of trailing 0's is \"" .
657 $out_mant_post_dec . "\".";
658 }
659
660 //If we're here and have an empty string, this is an allowed parsing exit.
661 //It corresponds to entering a decimal number without an exponent where an
662 //integer is required. This is probably a misunderstanding of some sort, but
663 //the caller should deal with it (not this function).
664 if (strlen($in_i2parse) == 0)
665 {
666 if ($in_debug)
667 {
668 $out_debug[] = "(Line " . __LINE__ . ") Plain decimal number detected.";
669 $out_debug[] = $debug_separator;
670 }
671
672 $out_display_value_scimatch = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
673 return;
674 }
675
676 //The next character has to be an "E" or "e". If it isn't, this is a gross
677 //parsing error.
678 if (StrToUpper(SubStr($in_i2parse, 0, 1)) != "E")
679 {
680 //The character is not an "E" or "e". Gross parsing error.
681
682 if ($in_debug)
683 {
684 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error, E/e not in place.";
685 $out_debug[] = $debug_separator;
686 }
687
688 $out_display_value_scimatch = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
689 //Should ignore the stuff we can't parse. Just form the mantissa.
690 $out_parse_errs = ISARITH_RC_UPERROR;
691 return;
692 }
693
694 //Remove the "E" or "e" character.
695 $in_i2parse = SubStr($in_i2parse, 1);
696
697 //If we created an empty string, this is a gross
698 //parse error.
699 if (strlen($in_i2parse) == 0)
700 {
701 if ($in_debug)
702 {
703 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error (empty string as intermediate result). Returning.";
704 $out_debug[] = $debug_separator;
705 }
706
707 $out_display_value_scimatch = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
708 //Should ignore the stuff we can't parse. Just form the mantissa.
709 $out_parse_errs = ISARITH_RC_UPERROR;
710 return;
711 }
712
713 //Debug info.
714 if ($in_debug)
715 {
716 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of E/e is \"" .
717 $in_i2parse . "\".";
718 }
719
720 //The next character has to be a sign character or a digit. If not, gross parsing error.
721 if (! STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "+-0123456789"))
722 {
723 if ($in_debug)
724 {
725 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error, char after E/e invalid.";
726 $out_debug[] = $debug_separator;
727 }
728
729 $out_display_value_scimatch = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
730 //Should ignore the stuff we can't parse. Just form the mantissa.
731 $out_parse_errs = ISARITH_RC_UPERROR;
732 return;
733 }
734
735 //Strip off and record the exponent sign, if any. There can be only one.
736 $out_exp_sign = "";
737 while
738 (
739 (strlen($in_i2parse) != 0)
740 &&
741 (
742 (SubStr($in_i2parse, 0, 1) == "-")
743 ||
744 (SubStr($in_i2parse, 0, 1) == "+")
745 )
746 )
747 {
748 if (SubStr($in_i2parse, 0, 1) == "-")
749 {
750 if (strlen($out_exp_sign))
751 {
752 //We are finding a second sign character. Not allowed.
753 if ($in_debug)
754 {
755 $out_debug[] = "(Line " . __LINE__ . ") Second exponent sign character found (illegal). Returning.";
756 $out_debug[] = $debug_separator;
757 }
758
759 $out_display_value_scimatch
760 = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
761 $out_parse_errs = ISARITH_RC_EMSGN;
762 return;
763 }
764 else
765 {
766 //Found a first minus sign. Record it.
767 if ($in_debug)
768 {
769 $out_debug[] = "(Line " . __LINE__ . ") Found a single exponent minus sign (legal).";
770 }
771
772 $out_exp_sign = "-";
773 }
774 }
775 else if (SubStr($in_i2parse, 0, 1) == "+")
776 {
777 if (strlen($out_exp_sign))
778 {
779 //We are finding a second exponent sign character. Not allowed.
780 if ($in_debug)
781 {
782 $out_debug[] = "(Line " . __LINE__ . ") Second exponent sign character found (illegal). Returning.";
783 $out_debug[] = $debug_separator;
784 }
785
786 $out_display_value_scimatch
787 = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
788 $out_parse_errs = ISARITH_RC_EMSGN;
789 return;
790 }
791 else
792 {
793 //Found a plus sign. Record it.
794 if ($in_debug)
795 {
796 $out_debug[] = "(Line " . __LINE__ . ") Exponent plus sign found (legal).";
797 }
798
799 $out_exp_sign = "+";
800 }
801 }
802
803 //Strip the character.
804 $in_i2parse = SubStr($in_i2parse, 1);
805 } //End while()
806
807 //If we created an empty string, this is a gross
808 //parse error.
809 if (strlen($in_i2parse) == 0)
810 {
811 if ($in_debug)
812 {
813 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error (empty string as intermediate result). Returning.";
814 $out_debug[] = $debug_separator;
815 }
816
817 $out_display_value_scimatch = "";
818 $out_parse_errs = ISARITH_RC_UPERROR;
819 return;
820 }
821
822 //Debug info.
823 if ($in_debug)
824 {
825 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of exponent sign is \"" .
826 $in_i2parse . "\".";
827 }
828
829 //The next character has to be a digit. If not, gross parsing error.
830 if (! STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
831 {
832 if ($in_debug)
833 {
834 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error, exponent digits not as expected.";
835 $out_debug[] = $debug_separator;
836 }
837
838 $out_display_value_scimatch = $out_mant_sign . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
839 //Should ignore the stuff we can't parse. Just form the mantissa.
840 $out_parse_errs = ISARITH_RC_UPERROR;
841 return;
842 }
843
844 //Remove the exponent digits.
845 while (
846 (strlen($in_i2parse))
847 &&
848 (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
849 )
850 {
851 $out_mant_exp_digits .= SubStr($in_i2parse, 0, 1);
852 $in_i2parse = SubStr($in_i2parse, 1);
853 }
854
855 //Debug info.
856 if ($in_debug)
857 {
858 $out_debug[] = "(Line " . __LINE__ . ") String created after removal of exponent digits is \"" .
859 $in_i2parse . "\".";
860 }
861
862 //Remove any leading 0's from the exponent. This may result in "".
863 while
864 (
865 (strlen($out_exp_digits))
866 &&
867 (SubStr($out_exp_digits, 0, 1) == "0")
868 )
869 {
870 $out_exp_digits = SubStr($out_exp_digits, 1);
871 }
872
873 //At this point, the string must be empty, otherwise there was stuff at the
874 //end of the number that is not digits.
875 if (strlen($in_i2parse) != 0)
876 {
877 if ($in_debug)
878 {
879 $out_debug[] = "(Line " . __LINE__ . ") Gross parsing error (non-digits at end of string). Returning.";
880 $out_debug[] = $debug_separator;
881 }
882
883 $out_display_value_scimatch = "";
884 $out_parse_errs = ISARITH_RC_UPERROR;
885 return;
886 }
887
888 //Debug info.
889 if ($in_debug)
890 {
891 $out_debug[] = "(Line " . __LINE__ . ") Setting up for normal non-error return.";
892 }
893
894 $out_display_value_scimatch = $out_mant_sign
895 . ISARITH_form_decimal_number($out_mant_pre_dec, $out_mant_post_dec);
896 if (strlen($out_exp_digits))
897 {
898 $out_display_value_scimatch = $out_display_value_scimatch
899 . "e"
900 . $out_exp_sign
901 . $out_exp_digits;
902 }
903
904 //Return fallthrough end of function.
905 }
906 //--------------------------------------------------------------------------------
907 //Assigns an arbitrarily long integer from a string. The string is converted
908 //to a simple integer, if possible.
909 //
910 //There are no limits on this function, so it would be possible to cause an
911 //out of memory or other condition by passing in an argument with an exponent
912 //of large absolute value. This function should be reserved for contexts
913 //where user input isn't the source or where it has already been sanitized.
914 //
915 //This function will accept strings to parse in a more relaxed format
916 //than canonical form (it parses things into canonical form). The
917 //specific relaxations are:
918 // a)A unary "+" is allowed, even on "0".
919 // b)Unary "-" is allowed even on "0".
920 // c)Commas are allowed, and need not be properly placed. Commas may occur
921 // even in exponents.
922 //
923 //The input string must be sanitized of spaces and tabs, even leading and trailing
924 //ones. The responsibility of removing these was deliberately pushed off onto the
925 //caller.
926 //
927 //Allowable formats are:
928 // a)Integer format (i.e. "25", "-2,352", "+325", etc.).
929 // b)Scientific notation, i.e. "3.12451234e+23".
930 // c)Optionally, "INAN".
931 //
932 function ISARITH_assign_from_string_nolimit
933 (
934 $in_i2parse,
935 //The string to parse. As mentioned above, all characters not to be
936 //considered, including leading and trailing blanks and tabs. The design
937 //decision to push this off on the caller was deliberate, as it gives the
938 //caller more latitude to decide what is allowed and not.
939 $in_inan_allowed,
940 //TRUE if INAN is allowed as an input string, or FALSE otherwise.
941 /* $in_nonint_behavior, */
942 //Behavior when non-integers are encountered (this may occur when a number is specified
943 //in scientific notation).
944 &$out_val,
945 //The output value parsed, as a simple integer string. This value will be
946 //FALSE iff there are errors.
947 &$out_errs,
948 //An integer reflecting a bitmask of errors (or lack thereof) encountered during
949 //the parse.
950 $debug_in,
951 //Flag, per the rules for PHP Boolean interpretation, that indicates whether to
952 //provide debug information per the $debug_out variable.
953 &$debug_out
954 //If $debug_in is TRUE, this will be populated with an array of strings containing
955 //debug information, otherwise this variable will be FALSE.
956 )
957 {
958
959 //Parse any digits before the decimal point, if there are any.
960 $parse_digits_pre_dec = "";
961 while (
962 (strlen($in_i2parse) != 0)
963 &&
964 (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
965 )
966 {
967 $parse_digits_pre_dec = $parse_digits_pre_dec . SubStr($in_i2parse, 0, 1);
968 $in_i2parse = SubStr($in_i2parse, 1);
969 }
970
971 //Parse the decimal point, if any. It is OK if we have an empty string
972 //at this point. There can be only one decimal point.
973 $parse_decimal_point_found = FALSE;
974 while
975 (
976 (strlen($in_i2parse) != 0)
977 &&
978 (SubStr($in_i2parse, 0, 1) == ".")
979 )
980 {
981 if ($parse_decimal_point_found)
982 {
983 //Illegal. Two decimal points.
984 $out_errs = ISARITH_RC_DPARSE;
985 return;
986 }
987 else
988 {
989 //Found a decimal point. This is fine, so long as it is the first one.
990 $parse_decimal_point_found = TRUE;
991 }
992
993 //Strip the character.
994 $in_i2parse = SubStr($in_i2parse, 1);
995 }
996
997 //Consume any digits that may occur after the decimal point.
998 $parse_digits_post_dec = "";
999 while (
1000 (strlen($in_i2parse) != 0)
1001 &&
1002 (STRFUNC_is_char_subset(SubStr($in_i2parse, 0, 1), "0123456789"))
1003 )
1004 {
1005 $parse_digits_post_dec = $parse_digits_post_dec . SubStr($in_i2parse, 0, 1);
1006 $in_i2parse = SubStr($in_i2parse, 1);
1007 }
1008
1009 //If the string remaining isn't empty, the only allowable character
1010 //is an "e" or "E". Once we have the "e" or "E", we must have an optional
1011 //sign and the digits.
1012 $parse_exp_marker_found = FALSE;
1013 $parse_exp_m_found = FALSE;
1014 $parse_exp_p_found = FALSE;
1015 $parse_exp_digits = "";
1016
1017 if (strlen($in_i2parse) != 0)
1018 {
1019 //Parse the exponent marker, if any.
1020 if (
1021 (SubStr($in_i2parse, 0, 1) == "e")
1022 ||
1023 (SubStr($in_i2parse, 0, 1) == "E")
1024 )
1025 {
1026 $parse_exp_marker_found = TRUE;
1027
1028 //Strip the character.
1029 $in_i2parse = SubStr($in_i2parse, 1);
1030 }
1031
1032 //If we created an empty string, this is a gross
1033 //parse error.
1034 if (strlen($in_i2parse) == 0)
1035 {
1036 $out_errs = ISARITH_RC_UPERROR;
1037 return;
1038 }
1039
1040 //If there is a second exponent marker, this is a parse failure.
1041 if (
1042 (SubStr($in_i2parse, 0, 1) == "e")
1043 ||
1044 (SubStr($in_i2parse, 0, 1) == "E")
1045 )
1046 {
1047 $out_errs = ISARITH_RC_EXPMPARSE;
1048 return;
1049 }
1050
1051 //Remove the optional sign from the exponent. There can be only one.
1052 while
1053 (
1054 (strlen($in_i2parse) != 0)
1055 &&
1056 (
1057 (SubStr($in_i2parse, 0, 1) == "-")
1058 ||
1059 (SubStr($in_i2parse, 0, 1) == "+")
1060 )
1061 )
1062 {
1063 if (SubStr($in_i2parse, 0, 1) == "-")
1064 {
1065 if ($parse_exp_m_found || $parse_exp_p_found)
1066 {
1067 //We are finding a second sign character. Not allowed.
1068 $out_errs = ISARITH_RC_EMSGN;
1069 return;
1070 }
1071 else
1072 {
1073 //Found a minus sign. Record it.
1074 $parse_exp_m_found = TRUE;
1075 }
1076 }
1077 else if (SubStr($in_i2parse, 0, 1) == "+")
1078 {
1079 if ($parse_exp_m_found || $parse_exp_p_found)
1080 {
1081 //We are finding a second sign character. Not allowed.
1082 $out_errs = ISARITH_RC_EMSGN;
1083 return;
1084 }
1085 else
1086 {
1087 //Found a plus sign. Record it.
1088 $parse_exp_p_found = TRUE;
1089 }
1090 }
1091
1092 //Strip the character.
1093 $in_i2parse = SubStr($in_i2parse, 1);
1094 }
1095
1096 //If we created an empty string, this is a gross
1097 //parse error.
1098 if (strlen($in_i2parse) == 0)
1099 {
1100 $out_errs = ISARITH_RC_UPERROR;
1101 return;
1102 }
1103
1104 //There have to be some digits now, after the "e"/"E" and the optional sign.
1105 if (!STRFUNC_is_char_subset($in_i2parse, "0123456789"))
1106 {
1107 $out_errs = ISARITH_RC_UPERROR;
1108 return;
1109 }
1110 else
1111 {
1112 //We have all digits left. Just assign them and rip off the leading 0's
1113 //if any.
1114 $parse_exp_digits = $in_i2_parse;
1115
1116 //TODO: Rip off the 0's. Will need to add a function to STRFUNCS.
1117 }
1118
1119 } //End if characters remaining.
1120 else
1121 {
1122 //No exponent field.
1123 }
1124
1125
1126 //At this point, the following variables are assigned.
1127 //
1128 //
1129 //
1130 //
1131 //
1132 //
1133 //
1134 //
1135 //
1136 //
1137 //
1138 //
1139 //
1140 //
1141 //
1142 //
1143 //
1144 //
1145 //
1146 //
1147 //
1148 //
1149 //
1150 //
1151 //
1152 //
1153 //
1154 //
1155 //
1156 //
1157
1158 }
1159
1160 //--------------------------------------------------------------------------------
1161 //--------------------------------------------------------------------------------
1162 //---- A S S I G N M E N T -----------------------------------------------------
1163 //--------------------------------------------------------------------------------
1164 //--------------------------------------------------------------------------------
1165 //Assigns an arbitrarily long integer from a string. The formats accepted are:
1166 // a)Integer format (i.e. "25", "-2,352", etc.).
1167 // b)Scientific notation, i.e. "3.12451234e+23".
1168 // c)Optionally, "INAN".
1169 //
1170 //It is the caller's responsibility to sanitize the string, including removing
1171 //leading and trailing blanks or tabs. This function by design requires a
1172 //string strictly as described above.
1173 //
1174 //The limits supplied should be chosen sanely to head off trouble with memory
1175 //blowups. The min and max limits will place limits on how exponents on the
1176 //value to parsed are expanded.
1177 //
1178 function ISARITH_assign_from_string
1179 (
1180 $in_i2parse,
1181 //The string to parse. As mentioned above, all characters not to be
1182 //considered, including leading and trailing blanks and tabs. The design
1183 //decision to push this off on the caller was deliberate, as it gives the
1184 //caller more latitude to decide what is allowed and not.
1185 $in_inan_allowed,
1186 //TRUE if INAN is allowed as an input string, or FALSE otherwise.
1187 $in_pval_min,
1188 $in_pval_max,
1189 //The minimum and maximum values that the parsed input may attain.
1190 //If the parsed value goes outside this range, an error is returned.
1191 &$out_val,
1192 //The output value parsed, as a simple integer string. This value will be
1193 //FALSE iff there are errors.
1194 &$out_errs
1195 //An integer reflecting the errors (or lack thereof) encountered during
1196 //the parse.
1197 )
1198 {
1199 //Assign default outputs.
1200 $out_val = FALSE;
1201 $out_errs = 0;
1202
1203 //Try to parse and assign the lower limit. If this can't be parsed,
1204 //can't continue.
1205 ISARITH_assign_from_string_nolimit(
1206 $in_pval_min,
1207 FALSE, //INAN is invalid as a limit, lower or upper.
1208 $pval_min_expanded,
1209 $local_conversion_errs
1210 );
1211
1212 if ($local_conversion_errs != 0)
1213 {
1214 //The minimum wouldn't parse successfully. Repackage this error for the
1215 //caller and return.
1216 $out_errs = ISARITH_RC_BADLIMIT;
1217 return;
1218 }
1219
1220 //Try to parse and assign the upper limit. If this can't be parsed,
1221 //can't continue.
1222 ISARITH_assign_from_string_nolimit(
1223 $in_pval_max,
1224 FALSE, //INAN is invalid as a limit, lower or upper.
1225 $pval_max_expanded,
1226 $local_conversion_errs
1227 );
1228
1229 if ($local_conversion_errs != 0)
1230 {
1231 //The maximum wouldn't parse successfully. Repackage this error for the
1232 //caller and return.
1233 $out_errs = ISARITH_RC_BADLIMIT;
1234 return;
1235 }
1236
1237
1238
1239 //Guts here.
1240 }
1241
1242 //--------------------------------------------------------------------------------
1243 //--------------------------------------------------------------------------------
1244 //--------------------------------------------------------------------------------
1245 //--------------------------------------------------------------------------------
1246 //--------------------------------------------------------------------------------
1247 function ISARITH_cmp($in_n1, $in_n2)
1248 {
1249 $rv = bccomp($in_n1, $in_n2);
1250
1251 return($rv);
1252 }
1253
1254 function ISARITH_add($in_n1, $in_n2)
1255 {
1256 $rv = bcadd($in_n1, $in_n2, 0);
1257
1258 return($rv);
1259 }
1260
1261 function ISARITH_sub($in_n1, $in_n2)
1262 {
1263 $rv = bcsub($in_n1, $in_n2, 0);
1264
1265 return($rv);
1266 }
1267
1268 function ISARITH_mul($in_n1, $in_n2)
1269 {
1270 $rv = bcmul($in_n1, $in_n2, 0);
1271
1272 return($rv);
1273 }
1274
1275 function ISARITH_div($in_n1, $in_n2)
1276 {
1277 $rv = bcdiv($in_n1, $in_n2, 0);
1278
1279 return($rv);
1280 }
1281
1282 function ISARITH_mod($in_n1, $in_n2)
1283 {
1284 $rv = bcmod($in_n1, $in_n2);
1285
1286 return($rv);
1287 }
1288
1289 function ISARITH_pow($in_base, $in_exponent)
1290 {
1291 $rv = bcpow($in_base, $in_exponent, 0);
1292
1293 return($rv);
1294 }
1295
1296 function ISARITH_powmod($in_base, $in_exponent, $in_modulus)
1297 {
1298 $rv = bcpowmod($in_base, $in_exponent, $in_modulus, 0);
1299
1300 return($rv);
1301 }
1302
1303 function ISARITH_sqrt($in_arg)
1304 {
1305 $rv = bcsqrt($in_arg, 0);
1306
1307 //Untested ... will need to sure above does not round.
1308
1309 return($rv);
1310 }
1311
1312 //Commanates.
1313 //
1314 function ISARITH_commanate($in_arg)
1315 {
1316 $prefix = "";
1317 if (SubStr($in_arg, 0, 1) == "-")
1318 {
1319 $prefix = "-";
1320 $in_arg = SubStr($in_arg, 1);
1321 }
1322
1323 $rv = "";
1324 while (strlen($in_arg) > 3)
1325 {
1326 $rv = "," . SubStr($in_arg, strlen($in_arg)-3) . $rv;
1327 $in_arg = SubStr($in_arg, 0, strlen($in_arg)-3);
1328 }
1329
1330 $rv = $prefix . $in_arg . $rv;
1331
1332 return($rv);
1333 }
1334
1335 //Commanates, but adds a string passed at the end of every
1336 //groupcount of groups of 3 digits, as a separator.
1337 //
1338 function ISARITH_commanate_wtext($in_arg, $in_groupcount, $in_groupsuffix)
1339 {
1340 $prefix = "";
1341 if (SubStr($in_arg, 0, 1) == "-")
1342 {
1343 $prefix = "-";
1344 $in_arg = SubStr($in_arg, 1);
1345 }
1346
1347 $rv = "";
1348 $groupnum = 0;
1349
1350 while (strlen($in_arg) > 3)
1351 {
1352 $groupnum++;
1353 if (($groupnum % $in_groupcount) == 0)
1354 $rv = "," . $in_groupsuffix . SubStr($in_arg, strlen($in_arg)-3) . $rv;
1355 else
1356 $rv = "," . SubStr($in_arg, strlen($in_arg)-3) . $rv;
1357
1358 $in_arg = SubStr($in_arg, 0, strlen($in_arg)-3);
1359 }
1360
1361 $rv = $prefix . $in_arg . $rv;
1362
1363 return($rv);
1364 }
1365
1366 function ISARITH_decommanate($in_arg)
1367 {
1368 $rv = STRFUNC_force_into_subset($in_arg, "-0123456789");
1369
1370 return($rv);
1371 }
1372 ?>

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25