Skip to content

Commit b7eb489

Browse files
Merge pull request #50 from SpiceSharp/development
Bug fix
2 parents e7d5227 + 526d19e commit b7eb489

16 files changed

Lines changed: 176 additions & 53 deletions

SpiceSharpBehavioral/Builders/Direct/ComplexBuilder.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ public class ComplexBuilder : IDirectBuilder<Complex>
1919
/// <inheritdoc/>
2020
public event EventHandler<VariableFoundEventArgs<Complex>> VariableFound;
2121

22-
/// <inheritdoc/>
23-
public double FudgeFactor { get; set; } = 1e-20;
24-
2522
/// <inheritdoc/>
2623
public double RelativeTolerance { get; set; } = 1e-6;
2724

@@ -45,7 +42,7 @@ public Complex Build(Node expression)
4542
case NodeTypes.Add: return Build(bn.Left) + Build(bn.Right);
4643
case NodeTypes.Subtract: return Build(bn.Left) - Build(bn.Right);
4744
case NodeTypes.Multiply: return Build(bn.Left) * Build(bn.Right);
48-
case NodeTypes.Divide: return HelperFunctions.SafeDivide(Build(bn.Left), Build(bn.Right), FudgeFactor);
45+
case NodeTypes.Divide: return HelperFunctions.SafeDivide(Build(bn.Left), Build(bn.Right));
4946
case NodeTypes.Modulo: return Build(bn.Left).Real % Build(bn.Right).Real;
5047
case NodeTypes.LessThan: return Build(bn.Left).Real < Build(bn.Right).Real ? 1.0 : 0.0;
5148
case NodeTypes.GreaterThan: return Build(bn.Left).Real > Build(bn.Right).Real ? 1.0 : 0.0;

SpiceSharpBehavioral/Builders/Direct/IDirectBuilder.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ namespace SpiceSharpBehavioral.Builders.Direct
88
/// <typeparam name="T">The value type.</typeparam>
99
public interface IDirectBuilder<T> : IBuilder<T>
1010
{
11-
/// <summary>
12-
/// Gets or sets the fudge factor.
13-
/// </summary>
14-
/// <value>
15-
/// The fudging factor.
16-
/// </value>
17-
double FudgeFactor { get; set; }
18-
1911
/// <summary>
2012
/// Gets or sets the relative tolerance.
2113
/// </summary>

SpiceSharpBehavioral/Builders/Direct/RealBuilder.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ public class RealBuilder : IDirectBuilder<double>
1616
/// <inheritdoc/>
1717
public event EventHandler<VariableFoundEventArgs<double>> VariableFound;
1818

19-
/// <inheritdoc/>
20-
public double FudgeFactor { get; set; } = 1e-20;
21-
2219
/// <inheritdoc/>
2320
public double RelativeTolerance { get; set; } = 1e-6;
2421

@@ -42,7 +39,7 @@ public double Build(Node expression)
4239
case NodeTypes.Add: return Build(bn.Left) + Build(bn.Right);
4340
case NodeTypes.Subtract: return Build(bn.Left) - Build(bn.Right);
4441
case NodeTypes.Multiply: return Build(bn.Left) * Build(bn.Right);
45-
case NodeTypes.Divide: return HelperFunctions.SafeDivide(Build(bn.Left), Build(bn.Right), FudgeFactor);
42+
case NodeTypes.Divide: return HelperFunctions.SafeDivide(Build(bn.Left), Build(bn.Right));
4643
case NodeTypes.Modulo: return Build(bn.Left) % Build(bn.Right);
4744
case NodeTypes.LessThan: return Build(bn.Left) < Build(bn.Right) ? 1.0 : 0.0;
4845
case NodeTypes.GreaterThan: return Build(bn.Left) > Build(bn.Right) ? 1.0 : 0.0;

SpiceSharpBehavioral/Builders/Direct/RealBuilderHelper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ namespace SpiceSharpBehavioral.Builders.Direct
1010
/// </summary>
1111
public static class RealBuilderHelper
1212
{
13+
// Random generator
1314
private static readonly Random _rnd = new Random();
1415

1516
/// <summary>
1617
/// A set of default functions.
1718
/// </summary>
18-
public static readonly Dictionary<string, Func<double[], double>> Defaults = new Dictionary<string, Func<double[], double>>
19+
public static readonly Dictionary<string, Func<double[], double>> Defaults = new Dictionary<string, Func<double[], double>>()
1920
{
2021
{ "abs", Abs },
2122
{ "sgn", Sgn },
@@ -111,7 +112,7 @@ private static void OnFunctionFound(object sender, FunctionFoundEventArgs<double
111112
private static double Nint(double[] args) => Math.Round(args.Check(1)[0], 0);
112113

113114
// Two-argument functions
114-
private static double Pow(double[] args) { args.Check(2); return Math.Pow(args[0], args[1]); }
115+
private static double Pow(double[] args) { args.Check(2); return HelperFunctions.Pow(args[0], args[1]); }
115116
private static double Pwr(double[] args) { args.Check(2); return HelperFunctions.Power(args[0], args[1]); }
116117
private static double Pwrs(double[] args) { args.Check(2); return HelperFunctions.Power2(args[0], args[1]); }
117118
private static double Min(double[] args) { args.Check(2); return Math.Min(args[0], args[1]); }

SpiceSharpBehavioral/Builders/Functions.cs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,25 @@ namespace SpiceSharpBehavioral.Builders
99
/// </summary>
1010
public static class HelperFunctions
1111
{
12+
/// <summary>
13+
/// Gets or sets a fudge factor for avoid edge cases (like division by 0).
14+
/// </summary>
15+
public static double FudgeFactor { get; set; } = 1e-32;
16+
1217
/// <summary>
1318
/// Divides two numbers while avoiding division by 0 using a fudge factor.
1419
/// </summary>
1520
/// <param name="left">The left argument.</param>
1621
/// <param name="right">The right argument.</param>
17-
/// <param name="fudgeFactor">The fudge factor.</param>
1822
/// <returns>
1923
/// The division.
2024
/// </returns>
21-
public static double SafeDivide(double left, double right, double fudgeFactor)
25+
public static double SafeDivide(double left, double right)
2226
{
2327
if (right < 0)
24-
right -= fudgeFactor;
28+
right -= FudgeFactor;
2529
else
26-
right += fudgeFactor;
30+
right += FudgeFactor;
2731
if (right.Equals(0.0))
2832
return double.PositiveInfinity;
2933
return left / right;
@@ -34,18 +38,17 @@ public static double SafeDivide(double left, double right, double fudgeFactor)
3438
/// </summary>
3539
/// <param name="left">The left argument.</param>
3640
/// <param name="right">The right argument.</param>
37-
/// <param name="fudgeFactor">The fudge factor.</param>
3841
/// <returns>
3942
/// The division.
4043
/// </returns>
41-
public static Complex SafeDivide(Complex left, Complex right, double fudgeFactor)
44+
public static Complex SafeDivide(Complex left, Complex right)
4245
{
43-
if (Math.Abs(right.Imaginary) < fudgeFactor)
46+
if (Math.Abs(right.Imaginary).Equals(0.0))
4447
{
4548
if (right.Real < 0)
46-
right -= fudgeFactor;
49+
right -= FudgeFactor;
4750
else
48-
right += fudgeFactor;
51+
right += FudgeFactor;
4952
}
5053
if (right.Real.Equals(0.0) && right.Imaginary.Equals(0.0))
5154
return double.PositiveInfinity;
@@ -82,7 +85,11 @@ public static bool Equals(double left, double right, double relTol, double absTo
8285
/// </returns>
8386
public static bool Equals(Complex left, Complex right, double relTol, double absTol)
8487
{
85-
if (!Equals(left.Real, right.Real) || !Equals(left.Imaginary, right.Imaginary))
88+
var tol = Math.Max(Math.Abs(left.Real), Math.Abs(right.Real)) * relTol + absTol;
89+
if (Math.Abs(left.Real - right.Real) > tol)
90+
return false;
91+
tol = Math.Max(Math.Abs(left.Imaginary), Math.Abs(right.Imaginary)) * relTol + absTol;
92+
if (Math.Abs(left.Imaginary - right.Imaginary) > tol)
8693
return false;
8794
return true;
8895
}
@@ -135,13 +142,31 @@ public static Complex Log10(Complex arg)
135142
return Complex.Log10(arg);
136143
}
137144

145+
/// <summary>
146+
/// Raises a number to a power.
147+
/// </summary>
148+
/// <param name="left">The left argument.</param>
149+
/// <param name="right">The right argument.</param>
150+
/// <returns></returns>
151+
public static double Pow(double left, double right)
152+
{
153+
if (left.Equals(0.0) && right <= 0.0)
154+
left += FudgeFactor;
155+
return Math.Pow(left, right);
156+
}
157+
138158
/// <summary>
139159
/// Raises a number to a power. The function is made symmetrical. Also known as "pwr".
140160
/// </summary>
141161
/// <param name="left">The left argument.</param>
142162
/// <param name="right">The right argument.</param>
143163
/// <returns>The result.</returns>
144-
public static double Power(double left, double right) => Math.Pow(Math.Abs(left), right);
164+
public static double Power(double left, double right)
165+
{
166+
if (left.Equals(0.0) && right <= 0.0)
167+
left += FudgeFactor;
168+
return Math.Pow(Math.Abs(left), right);
169+
}
145170

146171
/// <summary>
147172
/// Raises a number to a power. The function is made radially symmetrical. Also known as "pwr".
@@ -162,7 +187,11 @@ public static double Power2(double left, double right)
162187
if (left < 0)
163188
return -Math.Pow(-left, right);
164189
else
190+
{
191+
if (left.Equals(0.0) && right < 0.0)
192+
left += FudgeFactor;
165193
return Math.Pow(left, right);
194+
}
166195
}
167196

168197
/// <summary>
@@ -178,7 +207,12 @@ public static Complex Power2(Complex left, Complex right)
178207
if (left.Real < 0)
179208
return -Complex.Pow(-left.Real, right);
180209
else
181-
return Complex.Pow(left.Real, right);
210+
{
211+
double r = left.Real;
212+
if (r.Equals(0.0) && right.Real < 0.0)
213+
r += FudgeFactor;
214+
return Complex.Pow(r, right);
215+
}
182216
}
183217

184218
/// <summary>

SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilder.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ namespace SpiceSharpBehavioral.Builders.Functions
1212
/// <seealso cref="IFunctionBuilder{T}"/>
1313
public class ComplexFunctionBuilder : IFunctionBuilder<Complex>
1414
{
15-
/// <inheritdoc/>
16-
public double FudgeFactor { get; set; } = 1e-20;
17-
1815
/// <inheritdoc/>
1916
public double RelativeTolerance { get; set; } = 1e-6;
2017

SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilderHelper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SpiceSharp;
2+
using SpiceSharpBehavioral.Builders.Direct;
23
using SpiceSharpBehavioral.Diagnostics;
34
using SpiceSharpBehavioral.Parsers.Nodes;
45
using System;

SpiceSharpBehavioral/Builders/Functions/ComplexILState.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace SpiceSharpBehavioral.Builders.Functions
1212
/// </summary>
1313
public class ComplexILState : ILState<Complex>, IILComplexState
1414
{
15-
private static readonly MethodInfo _safeDiv = ((Func<Complex, Complex, double, Complex>)HelperFunctions.SafeDivide).GetMethodInfo();
15+
private static readonly MethodInfo _safeDiv = ((Func<Complex, Complex, Complex>)HelperFunctions.SafeDivide).GetMethodInfo();
1616
private static readonly MethodInfo _equals = ((Func<Complex, Complex, double, double, bool>)HelperFunctions.Equals).GetMethodInfo();
1717
private static readonly ConstructorInfo _cplx = typeof(Complex).GetTypeInfo().GetConstructor(new[] { typeof(double), typeof(double) });
1818
private static readonly MethodInfo _realPart = typeof(Complex).GetTypeInfo().GetProperty("Real", typeof(double)).GetGetMethod();
@@ -54,7 +54,6 @@ public override void Push(Node node)
5454
case NodeTypes.Divide:
5555
Push(bn.Left);
5656
Push(bn.Right);
57-
PushDouble(Builder.FudgeFactor);
5857
Generator.Emit(OpCodes.Call, _safeDiv);
5958
return;
6059

SpiceSharpBehavioral/Builders/Functions/IFunctionBuilder.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ namespace SpiceSharpBehavioral.Builders.Functions
88
/// <typeparam name="T">The value type.</typeparam>
99
public interface IFunctionBuilder<T> : IBuilder<Func<T>>
1010
{
11-
/// <summary>
12-
/// Gets or sets the fudge factor.
13-
/// </summary>
14-
/// <value>
15-
/// The fudging factor.
16-
/// </value>
17-
double FudgeFactor { get; set; }
18-
1911
/// <summary>
2012
/// Gets or sets the relative tolerance.
2113
/// </summary>

SpiceSharpBehavioral/Builders/Functions/RealFunctionBuilder.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ namespace SpiceSharpBehavioral.Builders.Functions
1111
/// <seealso cref="IFunctionBuilder{T}" />
1212
public class RealFunctionBuilder : IFunctionBuilder<double>
1313
{
14-
/// <inheritdoc/>
15-
public double FudgeFactor { get; set; } = 1e-20;
16-
1714
/// <inheritdoc/>
1815
public double RelativeTolerance { get; set; } = 1e-6;
1916

0 commit comments

Comments
 (0)