⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bigfloat.pm

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 PM
📖 第 1 页 / 共 5 页
字号:
      $rem = $x->copy();      }    $x->{sign} = $x->{sign} ne $y->sign() ? '-' : '+';     # check for / +-1 ( +/- 1E0)    if ($y_not_one)      {      # promote BigInts and it's subclasses (except when already a BigFloat)      $y = $self->new($y) unless $y->isa('Math::BigFloat');       # calculate the result to $scale digits and then round it      # a * 10 ** b / c * 10 ** d => a/c * 10 ** (b-d)      $MBI->_lsft($x->{_m},$MBI->_new($scale),10);      $MBI->_div ($x->{_m},$y->{_m});	# a/c      # correct exponent of $x      ($x->{_e},$x->{_es}) = _e_sub($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});      # correct for 10**scale      ($x->{_e},$x->{_es}) = _e_sub($x->{_e}, $MBI->_new($scale), $x->{_es}, '+');      $x->bnorm();		# remove trailing 0's      }    } # ende else $x != $y  # shortcut to not run through _find_round_parameters again  if (defined $params[0])    {    delete $x->{_a}; 				# clear before round    $x->bround($params[0],$params[2]);		# then round accordingly    }  else    {    delete $x->{_p}; 				# clear before round    $x->bfround($params[1],$params[2]);		# then round accordingly    }  if ($fallback)    {    # clear a/p after round, since user did not request it    delete $x->{_a}; delete $x->{_p};    }  if (wantarray)    {    if ($y_not_one)      {      $rem->bmod($y,@params);			# copy already done      }    if ($fallback)      {      # clear a/p after round, since user did not request it      delete $rem->{_a}; delete $rem->{_p};      }    return ($x,$rem);    }  $x;  }sub bmod   {  # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return reminder   # set up parameters  my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);  # objectify is costly, so avoid it  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))    {    ($self,$x,$y,$a,$p,$r) = objectify(2,@_);    }  return $x if $x->modify('bmod');  # handle NaN, inf, -inf  if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))    {    my ($d,$re) = $self->SUPER::_div_inf($x,$y);    $x->{sign} = $re->{sign};    $x->{_e} = $re->{_e};    $x->{_m} = $re->{_m};    return $x->round($a,$p,$r,$y);    }   if ($y->is_zero())    {    return $x->bnan() if $x->is_zero();    return $x;    }  return $x->bzero() if $x->is_zero() || ($x->is_int() &&  # check that $y == +1 or $y == -1:    ($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m})));  my $cmp = $x->bacmp($y);			# equal or $x < $y?  return $x->bzero($a,$p) if $cmp == 0;		# $x == $y => result 0  # only $y of the operands negative?   my $neg = 0; $neg = 1 if $x->{sign} ne $y->{sign};  $x->{sign} = $y->{sign};				# calc sign first  return $x->round($a,$p,$r) if $cmp < 0 && $neg == 0;	# $x < $y => result $x    my $ym = $MBI->_copy($y->{_m});    # 2e1 => 20  $MBI->_lsft( $ym, $y->{_e}, 10)    if $y->{_es} eq '+' && !$MBI->_is_zero($y->{_e});   # if $y has digits after dot  my $shifty = 0;			# correct _e of $x by this  if ($y->{_es} eq '-')			# has digits after dot    {    # 123 % 2.5 => 1230 % 25 => 5 => 0.5    $shifty = $MBI->_num($y->{_e}); 	# no more digits after dot    $MBI->_lsft($x->{_m}, $y->{_e}, 10);# 123 => 1230, $y->{_m} is already 25    }  # $ym is now mantissa of $y based on exponent 0  my $shiftx = 0;			# correct _e of $x by this  if ($x->{_es} eq '-')			# has digits after dot    {    # 123.4 % 20 => 1234 % 200    $shiftx = $MBI->_num($x->{_e});	# no more digits after dot    $MBI->_lsft($ym, $x->{_e}, 10);	# 123 => 1230    }  # 123e1 % 20 => 1230 % 20  if ($x->{_es} eq '+' && !$MBI->_is_zero($x->{_e}))    {    $MBI->_lsft( $x->{_m}, $x->{_e},10);	# es => '+' here    }  $x->{_e} = $MBI->_new($shiftx);  $x->{_es} = '+';   $x->{_es} = '-' if $shiftx != 0 || $shifty != 0;  $MBI->_add( $x->{_e}, $MBI->_new($shifty)) if $shifty != 0;    # now mantissas are equalized, exponent of $x is adjusted, so calc result  $x->{_m} = $MBI->_mod( $x->{_m}, $ym);  $x->{sign} = '+' if $MBI->_is_zero($x->{_m});		# fix sign for -0  $x->bnorm();  if ($neg != 0)	# one of them negative => correct in place    {    my $r = $y - $x;    $x->{_m} = $r->{_m};    $x->{_e} = $r->{_e};    $x->{_es} = $r->{_es};    $x->{sign} = '+' if $MBI->_is_zero($x->{_m});	# fix sign for -0    $x->bnorm();    }  $x->round($a,$p,$r,$y);	# round and return  }sub broot  {  # calculate $y'th root of $x    # set up parameters  my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);  # objectify is costly, so avoid it  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))    {    ($self,$x,$y,$a,$p,$r) = objectify(2,@_);    }  return $x if $x->modify('broot');  # NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0  return $x->bnan() if $x->{sign} !~ /^\+/ || $y->is_zero() ||         $y->{sign} !~ /^\+$/;  return $x if $x->is_zero() || $x->is_one() || $x->is_inf() || $y->is_one();    # we need to limit the accuracy to protect against overflow  my $fallback = 0;  my (@params,$scale);  ($x,@params) = $x->_find_round_parameters($a,$p,$r);  return $x if $x->is_nan();		# error in _find_round_parameters?  # no rounding at all, so must use fallback  if (scalar @params == 0)     {    # simulate old behaviour    $params[0] = $self->div_scale();	# and round to it as accuracy    $scale = $params[0]+4; 		# at least four more for proper round    $params[2] = $r;			# iound mode by caller or undef    $fallback = 1;			# to clear a/p afterwards    }  else    {    # the 4 below is empirical, and there might be cases where it is not    # enough...    $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined    }  # when user set globals, they would interfere with our calculation, so  # disable them and later re-enable them  no strict 'refs';  my $abr = "$self\::accuracy"; my $ab = $$abr; $$abr = undef;  my $pbr = "$self\::precision"; my $pb = $$pbr; $$pbr = undef;  # we also need to disable any set A or P on $x (_find_round_parameters took  # them already into account), since these would interfere, too  delete $x->{_a}; delete $x->{_p};  # need to disable $upgrade in BigInt, to avoid deep recursion  local $Math::BigInt::upgrade = undef;	# should be really parent class vs MBI  # remember sign and make $x positive, since -4 ** (1/2) => -2  my $sign = 0; $sign = 1 if $x->{sign} eq '-'; $x->{sign} = '+';  my $is_two = 0;  if ($y->isa('Math::BigFloat'))    {    $is_two = ($y->{sign} eq '+' && $MBI->_is_two($y->{_m}) && $MBI->_is_zero($y->{_e}));    }  else    {    $is_two = ($y == 2);    }  # normal square root if $y == 2:  if ($is_two)    {    $x->bsqrt($scale+4);    }  elsif ($y->is_one('-'))    {    # $x ** -1 => 1/$x    my $u = $self->bone()->bdiv($x,$scale);    # copy private parts over    $x->{_m} = $u->{_m};    $x->{_e} = $u->{_e};    $x->{_es} = $u->{_es};    }  else    {    # calculate the broot() as integer result first, and if it fits, return    # it rightaway (but only if $x and $y are integer):    my $done = 0;				# not yet    if ($y->is_int() && $x->is_int())      {      my $i = $MBI->_copy( $x->{_m} );      $MBI->_lsft( $i, $x->{_e}, 10 ) unless $MBI->_is_zero($x->{_e});      my $int = Math::BigInt->bzero();      $int->{value} = $i;      $int->broot($y->as_number());      # if ($exact)      if ($int->copy()->bpow($y) == $x)        {        # found result, return it        $x->{_m} = $int->{value};        $x->{_e} = $MBI->_zero();        $x->{_es} = '+';        $x->bnorm();        $done = 1;        }      }    if ($done == 0)      {      my $u = $self->bone()->bdiv($y,$scale+4);      delete $u->{_a}; delete $u->{_p};         # otherwise it conflicts      $x->bpow($u,$scale+4);                    # el cheapo      }    }  $x->bneg() if $sign == 1;    # shortcut to not run through _find_round_parameters again  if (defined $params[0])    {    $x->bround($params[0],$params[2]);		# then round accordingly    }  else    {    $x->bfround($params[1],$params[2]);		# then round accordingly    }  if ($fallback)    {    # clear a/p after round, since user did not request it    delete $x->{_a}; delete $x->{_p};    }  # restore globals  $$abr = $ab; $$pbr = $pb;  $x;  }sub bsqrt  {   # calculate square root  my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);  return $x if $x->modify('bsqrt');  return $x->bnan() if $x->{sign} !~ /^[+]/;	# NaN, -inf or < 0  return $x if $x->{sign} eq '+inf';		# sqrt(inf) == inf  return $x->round($a,$p,$r) if $x->is_zero() || $x->is_one();  # we need to limit the accuracy to protect against overflow  my $fallback = 0;  my (@params,$scale);  ($x,@params) = $x->_find_round_parameters($a,$p,$r);  return $x if $x->is_nan();		# error in _find_round_parameters?  # no rounding at all, so must use fallback  if (scalar @params == 0)     {    # simulate old behaviour    $params[0] = $self->div_scale();	# and round to it as accuracy    $scale = $params[0]+4; 		# at least four more for proper round    $params[2] = $r;			# round mode by caller or undef    $fallback = 1;			# to clear a/p afterwards    }  else    {    # the 4 below is empirical, and there might be cases where it is not    # enough...    $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined    }  # when user set globals, they would interfere with our calculation, so  # disable them and later re-enable them  no strict 'refs';  my $abr = "$self\::accuracy"; my $ab = $$abr; $$abr = undef;  my $pbr = "$self\::precision"; my $pb = $$pbr; $$pbr = undef;  # we also need to disable any set A or P on $x (_find_round_parameters took  # them already into account), since these would interfere, too  delete $x->{_a}; delete $x->{_p};  # need to disable $upgrade in BigInt, to avoid deep recursion  local $Math::BigInt::upgrade = undef;	# should be really parent class vs MBI  my $i = $MBI->_copy( $x->{_m} );  $MBI->_lsft( $i, $x->{_e}, 10 ) unless $MBI->_is_zero($x->{_e});  my $xas = Math::BigInt->bzero();  $xas->{value} = $i;  my $gs = $xas->copy()->bsqrt();	# some guess  if (($x->{_es} ne '-')		# guess can't be accurate if there are					# digits after the dot   && ($xas->bacmp($gs * $gs) == 0))	# guess hit the nail on the head?    {    # exact result, copy result over to keep $x    $x->{_m} = $gs->{value}; $x->{_e} = $MBI->_zero(); $x->{_es} = '+';    $x->bnorm();    # shortcut to not run through _find_round_parameters again    if (defined $params[0])      {      $x->bround($params[0],$params[2]);	# then round accordingly      }    else      {      $x->bfround($params[1],$params[2]);	# then round accordingly      }    if ($fallback)      {      # clear a/p after round, since user did not request it      delete $x->{_a}; delete $x->{_p};      }    # re-enable A and P, upgrade is taken care of by "local"    ${"$self\::accuracy"} = $ab; ${"$self\::precision"} = $pb;    return $x;    }   # sqrt(2) = 1.4 because sqrt(2*100) = 1.4*10; so we can increase the accuracy  # of the result by multipyling the input by 100 and then divide the integer  # result of sqrt(input) by 10. Rounding afterwards returns the real result.  # The following steps will transform 123.456 (in $x) into 123456 (in $y1)  my $y1 = $MBI->_copy($x->{_m});  my $length = $MBI->_len($y1);    # Now calculate how many digits the result of sqrt(y1) would have  my $digits = int($length / 2);  # But we need at least $scale digits, so calculate how many are missing  my $shift = $scale - $digits;  # That should never happen (we take care of integer guesses above)  # $shift = 0 if $shift < 0;   # Multiply in steps of 100, by shifting left two times the "missing" digits  my $s2 = $shift * 2;  # We now make sure that $y1 has the same odd or even number of digits than  # $x had. So when _e of $x is odd, we must shift $y1 by one digit left,  # because we always must multiply by steps of 100 (sqrt(100) is 10) and not  # steps of 10. The length of $x does not count, since an even or odd number  # of digits before the dot is not changed by adding an even number of digits  # after the dot (the result is still odd or even digits long).  $s2++ if $MBI->_is_odd($x->{_e});  $MBI->_lsft( $y1, $MBI->_new($s2), 10);  # now take the square root and truncate to integer  $y1 = $MBI->_sqrt($y1);  # By "shifting" $y1 right (by creating a negative _e) we calculate the final  # result, which is than later rounded to the desired scale.  # calculate how many zeros $x had after the '.' (or before it, depending  # on sign of $dat, the result should have half as many:  my $dat = $MBI->_num($x->{_e});  $dat = -$dat if $x->{_es} eq '-';  $dat += $length;  if ($dat > 0)    {    # no zeros after the dot (e.g. 1.23, 0.49 etc)    # preserve half as many digits before the dot than the input had     # (but round this "up")    $dat = int(($dat+1)/2);    }  else    {    $dat = int(($dat)/2);    }  $dat -= $MBI->_len($y1);  if ($dat < 0)    {    $dat = abs($dat);    $x->{_e} = $MBI->_new( $dat );    $x->{_es} = '-';    }  else    {        $x->{_e} = $MBI->_new( $dat );    $x->{_es} = '+';    }  $x->{_m} = $y1;  $x->bnorm();  # shortcut to not run through _find_round_parameters again  if (defined $params[0])    {    $x->bround($params[0],$params[2]);		# then round according

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -