mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 243 additions and 33 deletions
@ -0,0 +1,75 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Implements math operations using tolerant comparison.
|
|||
/// </summary>
|
|||
internal struct TolerantMath |
|||
{ |
|||
private readonly double epsilon; |
|||
|
|||
private readonly double negEpsilon; |
|||
|
|||
public TolerantMath(double epsilon) |
|||
{ |
|||
DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon)); |
|||
|
|||
this.epsilon = epsilon; |
|||
this.negEpsilon = -epsilon; |
|||
} |
|||
|
|||
public static TolerantMath Default { get; } = new TolerantMath(1e-8); |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> == 0
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsZero(double a) => a > this.negEpsilon && a < this.epsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> > 0
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsPositive(double a) => a > this.epsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> < 0
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsNegative(double a) => a < this.negEpsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> == <paramref name="b"/>
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool AreEqual(double a, double b) => this.IsZero(a - b); |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> > <paramref name="b"/>
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsGreater(double a, double b) => a > b + this.epsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> < <paramref name="b"/>
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsLess(double a, double b) => a < b - this.epsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> >= <paramref name="b"/>
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsGreaterOrEqual(double a, double b) => a >= b - this.epsilon; |
|||
|
|||
/// <summary>
|
|||
/// <paramref name="a"/> <= <paramref name="b"/>
|
|||
/// </summary>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; |
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
|
|||
using Xunit; |
|||
// ReSharper disable InconsistentNaming
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Helpers |
|||
{ |
|||
public class TolerantMathTests |
|||
{ |
|||
private readonly TolerantMath tolerantMath = new TolerantMath(0.1); |
|||
|
|||
[Theory] |
|||
[InlineData(0)] |
|||
[InlineData(0.01)] |
|||
[InlineData(-0.05)] |
|||
public void IsZero_WhenTrue(double a) |
|||
{ |
|||
Assert.True(this.tolerantMath.IsZero(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0.11)] |
|||
[InlineData(-0.101)] |
|||
[InlineData(42)] |
|||
public void IsZero_WhenFalse(double a) |
|||
{ |
|||
Assert.False(this.tolerantMath.IsZero(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0.11)] |
|||
[InlineData(100)] |
|||
public void IsPositive_WhenTrue(double a) |
|||
{ |
|||
Assert.True(this.tolerantMath.IsPositive(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(0.09)] |
|||
[InlineData(-0.1)] |
|||
[InlineData(-1000)] |
|||
public void IsPositive_WhenFalse(double a) |
|||
{ |
|||
Assert.False(this.tolerantMath.IsPositive(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(-0.11)] |
|||
[InlineData(-100)] |
|||
public void IsNegative_WhenTrue(double a) |
|||
{ |
|||
Assert.True(this.tolerantMath.IsNegative(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(-0.09)] |
|||
[InlineData(0.1)] |
|||
[InlineData(1000)] |
|||
public void IsNegative_WhenFalse(double a) |
|||
{ |
|||
Assert.False(this.tolerantMath.IsNegative(a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(4.2, 4.2)] |
|||
[InlineData(4.2, 4.25)] |
|||
[InlineData(-Math.PI, -Math.PI + 0.05)] |
|||
[InlineData(999999.2, 999999.25)] |
|||
public void AreEqual_WhenTrue(double a, double b) |
|||
{ |
|||
Assert.True(this.tolerantMath.AreEqual(a, b)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(1, 2)] |
|||
[InlineData(-1000000, -1000000.2)] |
|||
public void AreEqual_WhenFalse(double a, double b) |
|||
{ |
|||
Assert.False(this.tolerantMath.AreEqual(a, b)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(2, 1.8)] |
|||
[InlineData(-20, -20.2)] |
|||
[InlineData(0.1, -0.1)] |
|||
[InlineData(100, 10)] |
|||
public void IsGreater_IsLess_WhenTrue(double a, double b) |
|||
{ |
|||
Assert.True(this.tolerantMath.IsGreater(a, b)); |
|||
Assert.True(this.tolerantMath.IsLess(b, a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(2, 1.95)] |
|||
[InlineData(-20, -20.02)] |
|||
[InlineData(0.01, -0.01)] |
|||
[InlineData(999999, 999999.09)] |
|||
public void IsGreater_IsLess_WhenFalse(double a, double b) |
|||
{ |
|||
Assert.False(this.tolerantMath.IsGreater(a, b)); |
|||
Assert.False(this.tolerantMath.IsLess(b, a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(3, 2)] |
|||
[InlineData(3, 2.99)] |
|||
[InlineData(2.99, 3)] |
|||
[InlineData(-5, -6)] |
|||
[InlineData(-5, -5.05)] |
|||
[InlineData(-5.05, -5)] |
|||
public void IsGreaterOrEqual_IsLessOrEqual_WhenTrue(double a, double b) |
|||
{ |
|||
Assert.True(this.tolerantMath.IsGreaterOrEqual(a, b)); |
|||
Assert.True(this.tolerantMath.IsLessOrEqual(b, a)); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(2, 3)] |
|||
[InlineData(2.89, 3)] |
|||
[InlineData(-3, -2.89)] |
|||
public void IsGreaterOrEqual_IsLessOrEqual_WhenFalse(double a, double b) |
|||
{ |
|||
Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); |
|||
Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue