115 lines
3.2 KiB
C#
115 lines
3.2 KiB
C#
using BenchmarkDotNet.Attributes;
|
|
|
|
namespace Just.PreciseMath.Benchmarks;
|
|
|
|
/// <summary>Isolates ordinary/fallback exponent transitions, not special-value handling.</summary>
|
|
[MemoryDiagnoser]
|
|
[CategoriesColumn]
|
|
public class ArithmeticBoundaryBenchmarks
|
|
{
|
|
private DoubleDouble _addLeft;
|
|
private DoubleDouble _addRight;
|
|
private DoubleDouble _multiplyLeft;
|
|
private DoubleDouble _divideLeft;
|
|
private DoubleDouble _factor;
|
|
|
|
[Params(false, true)]
|
|
public bool Fallback { get; set; }
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
int offset = Fallback ? 1 : 0;
|
|
_addLeft = Pair(1020 + offset);
|
|
_addRight = Pair(1019);
|
|
_multiplyLeft = Pair(900 + offset);
|
|
_divideLeft = Pair(450 + offset);
|
|
_factor = DoubleDouble.FromComponents(1.125, Math.ScaleB(1.0, -56));
|
|
// Pin dispatch assumptions to the current source guards. Both signs/orders
|
|
// remain finite; boundary timing is intentionally separate from ordinary data.
|
|
if ((Math.ILogB(_addLeft.High) > 1020) != Fallback
|
|
|| (Math.ILogB(_multiplyLeft.High) + Math.ILogB(_factor.High) > 900) != Fallback
|
|
|| (Math.Abs(Math.ILogB(_divideLeft.High)) > 450) != Fallback)
|
|
{
|
|
throw new InvalidOperationException("Boundary fixture does not select the requested guard branch.");
|
|
}
|
|
}
|
|
|
|
private static DoubleDouble Pair(int exponent)
|
|
{
|
|
return DoubleDouble.FromComponents(Math.ScaleB(1.0, exponent), Math.ScaleB(1.0, exponent - 56));
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Addition")]
|
|
public DoubleDouble DDAdd()
|
|
{
|
|
return _addLeft + _addRight;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Addition")]
|
|
public DoubleDouble DDScalarAdd()
|
|
{
|
|
return _addLeft + _addRight.High;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Addition")]
|
|
public DoubleDouble ScalarDDAdd()
|
|
{
|
|
return _addLeft.High + _addRight;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Subtraction")]
|
|
public DoubleDouble DDSubtract()
|
|
{
|
|
return _addLeft - _addRight;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Subtraction")]
|
|
public DoubleDouble DDScalarSubtract()
|
|
{
|
|
return _addLeft - _addRight.High;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Subtraction")]
|
|
public DoubleDouble ScalarDDSubtract()
|
|
{
|
|
return _addLeft.High - _addRight;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Multiplication")]
|
|
public DoubleDouble DDMultiply()
|
|
{
|
|
return _multiplyLeft * _factor;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Multiplication")]
|
|
public DoubleDouble DDScalarMultiply()
|
|
{
|
|
return _multiplyLeft * _factor.High;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Multiplication")]
|
|
public DoubleDouble ScalarDDMultiply()
|
|
{
|
|
return _multiplyLeft.High * _factor;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Division")]
|
|
public DoubleDouble DDDivide()
|
|
{
|
|
return _divideLeft / _factor;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Division")]
|
|
public DoubleDouble DDScalarDivide()
|
|
{
|
|
return _divideLeft / _factor.High;
|
|
}
|
|
|
|
[Benchmark, BenchmarkCategory("Division")]
|
|
public DoubleDouble ScalarDDDivide()
|
|
{
|
|
return _factor.High / _divideLeft;
|
|
}
|
|
}
|