Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

performance and accuracy of pow() #4

Open
Patashu opened this issue Nov 20, 2017 · 2 comments
Open

performance and accuracy of pow() #4

Patashu opened this issue Nov 20, 2017 · 2 comments
Labels
is this optimal? possible performance improvements

Comments

@Patashu
Copy link
Owner

Patashu commented Nov 20, 2017

Several things need to be figured out about pow(). Copying the code as it stands now:

	pow(value) {
		//UN-SAFETY: We're assuming Decimal^number because number^Decimal or Decimal^Decimal is unheard of in incremental games.
	
		//TODO: Possibly implement slabdrill's generic fast track (with more precise tests)
		/*
		
		var temp = Math.pow(this.mantissa,value)
		if (Math.abs(temp) < 1.8e307) {
			return Decimal.fromMantissaExponent(temp*Math.pow(10,(this.exponent*value)%1), Math.floor(this.exponent*value));
		}

		*/
	
		//Fast track: If (this.exponent*value) is an integer and mantissa^value fits in a Number, we can do a very fast method.
		var temp = this.exponent*value;
		if (Number.isSafeInteger(temp))
		{
			var newMantissa = Math.pow(this.mantissa, value);
			if (Number.isFinite(newMantissa))
			{
				//TODO: This might actually be slower than the 'slow track' if pow is very large, because of the huge amount of normalization we have to do. For example, Decimal.pow(1.43534e-8, 1000) has to be normalized 156 times. Maybe only take fast track if abs(value) <= 10? (Alternatively normalization for very unnormalized numbers can be done)
				return Decimal.fromMantissaExponent(newMantissa, temp);
			}
		}
		
		return Decimal.exp(value*this.ln());
	}

sqrt() also has a potential optimization:

	static sqrt(value) {
		//TODO: If generic fast track pow is not used, implement slabdrill's sqrt and cbrt specific fast track like so:
		///if (this.exponent % 2 = 1) return Decimal.fromMantissaExponent(this.mantissa*3.16227766017, Math.floor(this.exponent/2));
		value = Decimal.fromValue(value);
		
		return value.sqrt();
	}
@Patashu
Copy link
Owner Author

Patashu commented Nov 21, 2017

sqrt, cbrt, sqr, cube are all replaced with their fast track version.

in pow itself, fast track 1 is neutral for performance over random pows, fast track 2 is detrimental for performance. So squeezing out more performance from here may be difficult.

Test used:

for (var i = 0; i < 1000000; ++i)
{
    var a = Decimal.randomDecimalForTesting(1000);
    var pow = Math.random()*20-10;
    if (Math.random()*2 < 1) { pow = Math.round(pow); }
    var result = Decimal.pow(a, pow);
}

EDIT: Fast track 2 might become faster if we don't need to normalize() and deliberately skip doing it.

EDIT 2: No good, we do need normalize().

@Patashu Patashu added is this optimal? possible performance improvements and removed enhancement labels Nov 21, 2017
@Patashu
Copy link
Owner Author

Patashu commented Nov 21, 2017

For comparison, SpeedCrunch’s pow is:

https://bitbucket.org/heldercorreia/speedcrunch/src/9cffa7b674890affcb877bfebc81d39c26b20dcc/src/math/floatpower.c?at=master&fileviewer=file-view-default
https://bitbucket.org/heldercorreia/speedcrunch/src/9cffa7b674890affcb877bfebc81d39c26b20dcc/src/math/floatipower.c?at=master&fileviewer=file-view-default

  1. if the exponent is integer, do an integer pow (described in floatipower.c)
  2. else do exp(ln(x)*exponent)

With no other fast tracks.

Todo:

  1. Look into if any of the integer pow code can/should be in break_infinity.js and if it speeds things up.
  2. Test performance of pow 1.5 hitting an integer, pow 1.5 not hitting an integer, pow 2 and random pows with current style and speed crunch style fast track 1. Keep whichever is faster overall.
  3. Test if sqrt and cbrt optimizations are actually faster or not.

Then everything is satisfied and this issue can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
is this optimal? possible performance improvements
Projects
None yet
Development

No branches or pull requests

1 participant