Skip to content

Commit

Permalink
Replaced number implementation with one based on 64 bit ints
Browse files Browse the repository at this point in the history
  • Loading branch information
martindevans committed Jul 30, 2020
1 parent dca3122 commit bc6eb29
Show file tree
Hide file tree
Showing 19 changed files with 404 additions and 110 deletions.
2 changes: 1 addition & 1 deletion Yolol.Analysis/ControlFlowGraph/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private void HandleGoto(IMutableControlFlowGraph cfg, Goto @goto, IMutableBasicB
if (dest.Type == Execution.Type.Number)
{
// We know exactly where this is going, jump to that line
var line = Math.Clamp((int)dest.Number.Value, 1, _maxLines);
var line = Math.Clamp((int)dest.Number, 1, _maxLines);
var destBlock = GetLineEntryBlock(cfg, line);
cfg.CreateEdge(block, destBlock, EdgeType.GotoConstNum);
}
Expand Down
2 changes: 1 addition & 1 deletion Yolol.Analysis/DataFlowGraph/DataFlowGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ protected override IDataFlowGraphExpressionNode Visit(Negate neg)
protected override IDataFlowGraphExpressionNode Visit(ConstantNumber con)
{

var op = new InputConst(Guid.NewGuid(), con.Value.Value);
var op = new InputConst(Guid.NewGuid(), new Value(con.Value));
_dataFlowGraph._inputs.Add(op);
return op;
}
Expand Down
8 changes: 4 additions & 4 deletions Yolol.Analysis/SAT/IModelVariable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal void AssertEq(Value value)
switch (value.Type)
{
case Type.Number:
_model.Solver.Assert(ctx.MkEq(_numValue, _model.Context.MkInt((value.Number.Value * Number.Scale).ToString(CultureInfo.InvariantCulture))));
_model.Solver.Assert(ctx.MkEq(_numValue, _model.Context.MkInt(((long)value.Number * Number.Scale).ToString(CultureInfo.InvariantCulture))));
return;

case Type.String:
Expand Down Expand Up @@ -493,7 +493,7 @@ ModelVariable GetOrCreateVar(BaseExpression sub)
if (sub is ConstantNumber num)
{
var n = _model.GetOrCreateVariable(new VariableName(Guid.NewGuid().ToString()));
n.AssertEq(num.Value.Value);
n.AssertEq(num.Value);
return n;
}

Expand Down Expand Up @@ -536,7 +536,7 @@ public bool CanBeValue(Value v)
return _model.Solver.IsSatisfiable(
ctx.MkAnd(
ctx.MkEq(_type, _model.NumType),
ctx.MkEq(_numValue, _model.Context.MkInt((v.Number.Value * Number.Scale).ToString()))
ctx.MkEq(_numValue, _model.Context.MkInt(((long)v.Number * Number.Scale).ToString()))
)
);
}
Expand All @@ -554,7 +554,7 @@ public bool CannotBeOtherValue(Value v)
return !_model.Solver.IsSatisfiable(ctx.MkNot(ctx.MkEq(_strValue, _model.Context.MkString(v.String))));

if (v.Type == Type.Number)
return !_model.Solver.IsSatisfiable(ctx.MkNot(ctx.MkEq(_numValue, _model.Context.MkInt((v.Number.Value * Number.Scale).ToString()))));
return !_model.Solver.IsSatisfiable(ctx.MkNot(ctx.MkEq(_numValue, _model.Context.MkInt(((long)v.Number * Number.Scale).ToString()))));

throw new NotSupportedException($"unknown value type {v.Type}");
}
Expand Down
8 changes: 4 additions & 4 deletions Yolol.Analysis/TreeVisitor/Reduction/ConstantCompressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void Submit(BaseExpression exp)
var b = idx / 10m;
try
{
var log = Math.Log((double)value.Value, (double)b);
var log = Math.Log((double)(decimal)value, (double)b);
if (double.IsNaN(log))
continue;

Expand Down Expand Up @@ -146,10 +146,10 @@ private static BaseExpression BestFraction(Number number)
}
}

if (number.Value >= 1)
if (number >= 1)
return new ConstantNumber(number);

var (fn, fd) = RealToFraction((double)number.Value, 0.001f);
var (fn, fd) = RealToFraction((double)number, 0.001f);

var replacement = new Divide(new ConstantNumber((decimal)fn), new ConstantNumber((decimal)fd));

Expand All @@ -164,7 +164,7 @@ private static BaseExpression BestFraction(Number number)
var atan = new ArcTan(new ConstantNumber(number)).TryStaticEvaluate();
if (!atan.HasValue)
return null;
var atanFloor = (long)atan.Value.Number.Value;
var atanFloor = (long)(decimal)atan.Value.Number;

var offset = number - atan.Value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected override BaseExpression Visit(Multiply mul)
{
BaseExpression? HandleSingleSideNumber(Number number, BaseExpression other)
{
return number.Value switch {
return (long)number switch {
-1 => base.Visit(new Negate(new Bracketed(other))),
0 => new ConstantNumber(0),
1 => base.Visit(other),
Expand Down Expand Up @@ -86,7 +86,7 @@ protected override BaseExpression Visit(Divide div)
if (!rv.HasValue)
return base.Visit(div);

return rv.Value.Value switch {
return (long)rv.Value switch {
-1 => base.Visit(new Negate(new Bracketed(base.Visit(div.Left)))),
0 => new ErrorExpression(),
1 => base.Visit(new Bracketed(base.Visit(div.Left))),
Expand All @@ -98,7 +98,7 @@ protected override BaseExpression Visit(Add add)
{
BaseExpression? HandleSingleSideNumber(Number number, BaseExpression other)
{
return number.Value switch
return (long)number switch
{
0 => base.Visit(new Bracketed(other)),
_ => null,
Expand Down Expand Up @@ -149,7 +149,7 @@ protected override BaseExpression Visit(Exponent exp)
if (!rv.HasValue)
return base.Visit(exp);

return rv.Value.Value switch {
return (long)rv.Value switch {
0 => base.Visit(new ConstantNumber(1)),
1 => base.Visit(new Bracketed(base.Visit(exp.Left))),
-1 => base.Visit(new Divide(new ConstantNumber(1), new Bracketed(exp.Left))),
Expand Down
2 changes: 1 addition & 1 deletion Yolol.Cylon/JSON/YololValueConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override void WriteJson(JsonWriter writer, Value value, JsonSerializer se
if (value.Type == Execution.Type.String)
writer.WriteValue(value.String);
else
writer.WriteValue(value.Number.Value);
writer.WriteValue((decimal)value.Number);
}

public override Value ReadJson(JsonReader reader, Type objectType, Value existingValue, bool hasExistingValue, JsonSerializer serializer)
Expand Down
104 changes: 48 additions & 56 deletions Yolol/Execution/Number.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,27 @@

namespace Yolol.Execution
{
public struct Number
public readonly struct Number
: IEquatable<Number>
{
public const int Scale = 1000;
public const int Decimals = 3;

public static readonly Number MinValue = new Number(-9223372036854775.808m);
public static readonly Number MaxValue = new Number(9223372036854775.807m);
public static readonly Number One = new Number(1);
public static readonly Number MinValue = new Number(long.MinValue);
public static readonly Number MaxValue = new Number(long.MaxValue);
public static readonly Number One = new Number(1000);
public static readonly Number Zero = new Number(0);

public decimal Value { get; }
private long Value { get; }

private Number(decimal num)
private Number(long num)
{
Value = num;
}

private Number Truncate()
{
var d = Value;

// https://stackoverflow.com/a/43639947/108234
var r = Math.Round(d, Decimals);
if (d > 0 && r > d)
return new Number(r - new decimal(1, 0, 0, false, Decimals));
else if (d < 0 && r < d)
return new Number(r + new decimal(1, 0, 0, false, Decimals));

return new Number(r);

// Naieve approach
//return new Number(Math.Truncate(Value * Scale) / Scale);
}

private Number RangeCheck()
{
if (Value > MaxValue.Value)
return MaxValue;

if (Value < MinValue.Value)
return MinValue;

return this;
}

private static Number SafeNew(decimal num)
{
return new Number(num).Truncate().RangeCheck();
}

public string ToString(CultureInfo culture)
{
return Value.ToString("0.###", culture);
return ((decimal)Value / Scale).ToString(culture);
}

public override string ToString()
Expand All @@ -66,7 +33,7 @@ public override string ToString()

public bool Equals(Number other)
{
return this == other;
return Value == other.Value;
}

public override bool Equals(object obj)
Expand All @@ -81,64 +48,89 @@ public override int GetHashCode()

public static Number Parse(string s)
{
// First check if the number is so colossal that a decimal can't hold it
// First check if the number is out of the valid range
var d = double.Parse(s);
if (d >= (double)MaxValue.Value)
if (d >= MaxValue.Value)
return MaxValue;
else if (d <= (double)MinValue.Value)
else if (d <= MinValue.Value)
return MinValue;

// It's within the safe range, parse as decimal
return SafeNew(decimal.Parse(s));
return decimal.Parse(s);
}

public static implicit operator Number(int i)
{
return new Number(i);
return new Number(i * (long)Scale);
}

public static explicit operator Number(double i)
{
return SafeNew((decimal)i);
var n = i * Scale;
if (n > MaxValue.Value)
return MaxValue;
if (n < MinValue.Value)
return MinValue;

return new Number((long)n);
}

public static implicit operator Number(decimal d)
{
return SafeNew(d);
var n = d * Scale;
if (n > MaxValue.Value)
return MaxValue;
if (n < MinValue.Value)
return MinValue;

return new Number((long)(d * Scale));
}

public static explicit operator decimal(Number n)
{
return ((decimal)n.Value) / Scale;
}

public static explicit operator int(Number n)
{
return (int)(n.Value / Scale);
}

public static explicit operator float(Number n)
{
return ((float)n.Value) / Scale;
}

public static Number operator %(Number l, Number r)
{
var v = new Number(l.Value % r.Value);
return v.Truncate();
return new Number(l.Value % r.Value);
}

public static Number operator *(Number l, Number r)
{
return SafeNew(l.Value * r.Value);
return new Number((l.Value * r.Value) / Scale);
}

public static Number operator /(Number l, Number r)
{
if (r == Zero)
throw new ExecutionException("Divide by zero");

return SafeNew(l.Value / r.Value);
return new Number((l.Value * Scale) / r.Value);
}

public static Number operator +(Number l, Number r)
{
return SafeNew(l.Value + r.Value);
return new Number(l.Value + r.Value);
}

public static Number operator -(Number l, Number r)
{
return SafeNew(l.Value - r.Value);
return new Number(l.Value - r.Value);
}

public static Number operator -(Number n)
{
return new Number(-n.Value).RangeCheck();
return new Number(-n.Value);
}

public static bool operator >(Number l, Number r)
Expand Down
Loading

0 comments on commit bc6eb29

Please sign in to comment.