using BenchmarkDotNet.Attributes; namespace Just.PreciseMath.Benchmarks; /// Measures independent array operations, including loads, stores, and loop overhead. [MemoryDiagnoser] [CategoriesColumn] public class ArithmeticThroughputBenchmarks { private DoubleDouble[] _left = []; private DoubleDouble[] _right = []; private double[] _scalarLeft = []; private double[] _scalarRight = []; private readonly DoubleDouble[] _results = new DoubleDouble[ArithmeticInputs.Count]; private readonly double[] _doubleResults = new double[ArithmeticInputs.Count]; [Params("BinaryExact", "DecimalResidual", "BothResidual", "Mixed", "SignsAndScales", "Cancellation")] public string Scenario { get; set; } = "BothResidual"; [GlobalSetup] public void Setup() { ArithmeticInputs inputs = ArithmeticInputs.Create(Scenario, false); _left = inputs.Left; _right = inputs.Right; _scalarLeft = Array.ConvertAll(_left, value => value.High); _scalarRight = Array.ConvertAll(_right, value => value.High); } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Addition")] public DoubleDouble[] DDAdd() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] + _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Addition")] public DoubleDouble[] DDScalarAdd() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] + _scalarRight[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Addition")] public DoubleDouble[] ScalarDDAdd() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _scalarLeft[i] + _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Addition")] public double[] DoubleAdd() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _doubleResults[i] = _scalarLeft[i] + _scalarRight[i]; } return _doubleResults; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Subtraction")] public DoubleDouble[] DDSubtract() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] - _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Subtraction")] public DoubleDouble[] DDScalarSubtract() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] - _scalarRight[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Subtraction")] public DoubleDouble[] ScalarDDSubtract() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _scalarLeft[i] - _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Subtraction")] public double[] DoubleSubtract() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _doubleResults[i] = _scalarLeft[i] - _scalarRight[i]; } return _doubleResults; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Multiplication")] public DoubleDouble[] DDMultiply() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] * _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Multiplication")] public DoubleDouble[] DDScalarMultiply() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] * _scalarRight[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Multiplication")] public DoubleDouble[] ScalarDDMultiply() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _scalarLeft[i] * _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Multiplication")] public double[] DoubleMultiply() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _doubleResults[i] = _scalarLeft[i] * _scalarRight[i]; } return _doubleResults; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Division")] public DoubleDouble[] DDDivide() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] / _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Division")] public DoubleDouble[] DDScalarDivide() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _left[i] / _scalarRight[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Division")] public DoubleDouble[] ScalarDDDivide() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _results[i] = _scalarLeft[i] / _right[i]; } return _results; } [Benchmark(OperationsPerInvoke = ArithmeticInputs.Count), BenchmarkCategory("Division")] public double[] DoubleDivide() { for (int i = 0; i < ArithmeticInputs.Count; i++) { _doubleResults[i] = _scalarLeft[i] / _scalarRight[i]; } return _doubleResults; } }