BF mode Feedback#2

In BF mode the $calc() operator ^ causes a GPF when the return value is too long. I'm hoping the fix is just to defend against long strings returned from the libary, and not that the library itself would need to be slowed down to defend against big internal values. I haven't found the problem in multiplying, where it changes the value to zero when it's too big.

//var %a.bf 1 $+ $str(0,5168) | echo -a $len( $calc(%a.bf * %a.bf) ) -> 10337 ok
//var %a.bf 1 $+ $str(0,5169) | echo -a $calc(%a.bf * %a.bf) -> 0 too-big=zero ok

//var -s %a.bf $len($calc(10^10359)) ok
//var -s %a.bf $len($calc(10^10360)) gpf

--

Another example of dropping a digits, this time a whole lotta. The string should be longer in a smaller outbase

//var -s %digits 60 | echo -a $bigfloat $len( $base(1 $+ $str(0,%digits),10,9) )

result: $false 48

... and even for outbase 36 the number is way to short.

--

Quote
Fix for the m_apm_integer_pow_nr function:

This looks like the function that the $calc operator ^ should be using under-the-hood when the exponent is an integer, and I hope the ^ and $base() problems are caused by using the other function designed to do roundings, and switching to this will fix it easily.

But this is separate from that issue. If the '^' operator wrapper is not doing it already, the integer_pow should have an additional early exit - for the base being 0 or 1. Since 0^positive=0 and 1^positive=1, the check can just return 'x' if 'x' is less than 2, and I assume it would look like so.

if (n < 2) {m_apm_copy(r, n ? x : MM_One); return;}
if (x < 2) {m_apm_copy(r, x); return;}

---

Looks like I spoke a little too soon about $round being golden. While $calc outputs a fraction up to length 30, it looks like $round can only output length 20.

//var -s %a.bf $calc(0.123456789012345678941234567894) , %b.bf $round(%a.bf,30)
* Set %a.bf to 0.123456789012345678941234567894
* Set %b.bf to 0.12345678901234567894

However, it does look like $round always rounds a 21st digit '5' up, even if there is nothing beyond that 21st digit.

--

As far as the rounding done by $calc itself, the rounding is slightly different than before. The 1st example creates an internal 7-digit fraction ending with '5', and under the older doubles method, calc sometimes rounds the 7th digit 5 up or down, due to the known float rounding issues.

//bigfloat off | var %i 1 , %list | while (%i isnum 1-100) { var %list %list $calc(%i + 25/10^7) | inc %i } | echo -a round: %list

But under BF mode, it looks like it's always rounding a 31st digit 5 down. If changing the 25.0 to 26, it always rounds the 30th digit up. But 25.0 rounds down. However, that's the only case I've found $calc chopping off the 5, because if editing the 25.0 to 25.000000000000001 or even having a ridiculous number of zeroes in there, it sees the extra precision somehow and rounds it up.

//bigfloat on | var %i 1 , %list | while (%i isnum 1-100) { var %list %list $calc(%i + 25.0/10^31) | inc %i } | echo -a round: %list

So in conclusion, so far this is the only 'wrong' round I've found in BFcalc so far, and only seems to happen when the fraction is exactly 31 digits and ends with a 5.

--

I'm wondering if the .deg prop for the trig functions is using a double for either the 360 or the pi?

//echo -a %null.bf $bigfloat $cos(270).deg

result: -0.000000000000000000003965074919

As for inputs 360 degrees or greater, when they're measured in radians it's probably best to leave them alone, but perhaps in .deg mode the large inputs should be mod-360? I can see scripts assuming 360 degrees gives the same answer as zero.

//echo -a %null.bf $sin(360).deg $sin(3600).deg

result: -0.000000000000000000005286766559

--

If there won't be something to override this next behavior, it's something scriptors will need to be aware of, as they may have unwanted results if they use a BF-mode identifier in the middle of an echo.

//var -s %a.bf 0 | echo -a $calc(1/7) $bigfloat $calc(%a.bf) $bigfloat $calc(1/7)

0.142857 $false 0 $true 0.142857142857142857142857142857

And even replacing the $calc(%a.bf) with custom alias $justreturn$1(%a.bf) is enough to trigger flipping to BF mode. The only way I found to shield %a.bf from flipping into BF mode is $eval(%a.bf,0) and that's no help.

Maybe a $bigfloatoff in the middle of a command line that flips the mode, or something somewhat like $shield( $return$1(%a.bf) ) that allows an identifier to use a variable without flipping the whole echo to BF mode. Even $unsafe( %null.bf ) flips to BF mode.

//echo -a $bigfloat $unsafe(%null.bf) $bigfloat
result: $false $true

Wouldn't need a $bigfloaton identifier because $left(%null.bf,0) does that.