Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
4.5 KiB

  1. package bigrat;
  2. require "bigint.pl";
  3. #
  4. # This library is no longer being maintained, and is included for backward
  5. # compatibility with Perl 4 programs which may require it.
  6. #
  7. # In particular, this should not be used as an example of modern Perl
  8. # programming techniques.
  9. #
  10. # Arbitrary size rational math package
  11. #
  12. # by Mark Biggar
  13. #
  14. # Input values to these routines consist of strings of the form
  15. # m|^\s*[+-]?[\d\s]+(/[\d\s]+)?$|.
  16. # Examples:
  17. # "+0/1" canonical zero value
  18. # "3" canonical value "+3/1"
  19. # " -123/123 123" canonical value "-1/1001"
  20. # "123 456/7890" canonical value "+20576/1315"
  21. # Output values always include a sign and no leading zeros or
  22. # white space.
  23. # This package makes use of the bigint package.
  24. # The string 'NaN' is used to represent the result when input arguments
  25. # that are not numbers, as well as the result of dividing by zero and
  26. # the sqrt of a negative number.
  27. # Extreamly naive algorthims are used.
  28. #
  29. # Routines provided are:
  30. #
  31. # rneg(RAT) return RAT negation
  32. # rabs(RAT) return RAT absolute value
  33. # rcmp(RAT,RAT) return CODE compare numbers (undef,<0,=0,>0)
  34. # radd(RAT,RAT) return RAT addition
  35. # rsub(RAT,RAT) return RAT subtraction
  36. # rmul(RAT,RAT) return RAT multiplication
  37. # rdiv(RAT,RAT) return RAT division
  38. # rmod(RAT) return (RAT,RAT) integer and fractional parts
  39. # rnorm(RAT) return RAT normalization
  40. # rsqrt(RAT, cycles) return RAT square root
  41. # Convert a number to the canonical string form m|^[+-]\d+/\d+|.
  42. sub main'rnorm { #(string) return rat_num
  43. local($_) = @_;
  44. s/\s+//g;
  45. if (m#^([+-]?\d+)(/(\d*[1-9]0*))?$#) {
  46. &norm($1, $3 ? $3 : '+1');
  47. } else {
  48. 'NaN';
  49. }
  50. }
  51. # Normalize by reducing to lowest terms
  52. sub norm { #(bint, bint) return rat_num
  53. local($num,$dom) = @_;
  54. if ($num eq 'NaN') {
  55. 'NaN';
  56. } elsif ($dom eq 'NaN') {
  57. 'NaN';
  58. } elsif ($dom =~ /^[+-]?0+$/) {
  59. 'NaN';
  60. } else {
  61. local($gcd) = &'bgcd($num,$dom);
  62. $gcd =~ s/^-/+/;
  63. if ($gcd ne '+1') {
  64. $num = &'bdiv($num,$gcd);
  65. $dom = &'bdiv($dom,$gcd);
  66. } else {
  67. $num = &'bnorm($num);
  68. $dom = &'bnorm($dom);
  69. }
  70. substr($dom,$[,1) = '';
  71. "$num/$dom";
  72. }
  73. }
  74. # negation
  75. sub main'rneg { #(rat_num) return rat_num
  76. local($_) = &'rnorm(@_);
  77. tr/-+/+-/ if ($_ ne '+0/1');
  78. $_;
  79. }
  80. # absolute value
  81. sub main'rabs { #(rat_num) return $rat_num
  82. local($_) = &'rnorm(@_);
  83. substr($_,$[,1) = '+' unless $_ eq 'NaN';
  84. $_;
  85. }
  86. # multipication
  87. sub main'rmul { #(rat_num, rat_num) return rat_num
  88. local($xn,$xd) = split('/',&'rnorm($_[$[]));
  89. local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
  90. &norm(&'bmul($xn,$yn),&'bmul($xd,$yd));
  91. }
  92. # division
  93. sub main'rdiv { #(rat_num, rat_num) return rat_num
  94. local($xn,$xd) = split('/',&'rnorm($_[$[]));
  95. local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
  96. &norm(&'bmul($xn,$yd),&'bmul($xd,$yn));
  97. }
  98. # addition
  99. sub main'radd { #(rat_num, rat_num) return rat_num
  100. local($xn,$xd) = split('/',&'rnorm($_[$[]));
  101. local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
  102. &norm(&'badd(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
  103. }
  104. # subtraction
  105. sub main'rsub { #(rat_num, rat_num) return rat_num
  106. local($xn,$xd) = split('/',&'rnorm($_[$[]));
  107. local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
  108. &norm(&'bsub(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
  109. }
  110. # comparison
  111. sub main'rcmp { #(rat_num, rat_num) return cond_code
  112. local($xn,$xd) = split('/',&'rnorm($_[$[]));
  113. local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
  114. &bigint'cmp(&'bmul($xn,$yd),&'bmul($yn,$xd));
  115. }
  116. # int and frac parts
  117. sub main'rmod { #(rat_num) return (rat_num,rat_num)
  118. local($xn,$xd) = split('/',&'rnorm(@_));
  119. local($i,$f) = &'bdiv($xn,$xd);
  120. if (wantarray) {
  121. ("$i/1", "$f/$xd");
  122. } else {
  123. "$i/1";
  124. }
  125. }
  126. # square root by Newtons method.
  127. # cycles specifies the number of iterations default: 5
  128. sub main'rsqrt { #(fnum_str[, cycles]) return fnum_str
  129. local($x, $scale) = (&'rnorm($_[$[]), $_[$[+1]);
  130. if ($x eq 'NaN') {
  131. 'NaN';
  132. } elsif ($x =~ /^-/) {
  133. 'NaN';
  134. } else {
  135. local($gscale, $guess) = (0, '+1/1');
  136. $scale = 5 if (!$scale);
  137. while ($gscale++ < $scale) {
  138. $guess = &'rmul(&'radd($guess,&'rdiv($x,$guess)),"+1/2");
  139. }
  140. "$guess"; # quotes necessary due to perl bug
  141. }
  142. }
  143. 1;