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

Annotation of /to_be_filed/webprojs/php_libraries/php_lib_uculib_com/int_string_arithmetic.inc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (hide annotations) (download)
Sat Oct 8 23:35:33 2016 UTC (7 years, 8 months ago) by dashley
File size: 47430 byte(s)
Initial commit.
1 dashley 35 <?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