From 00f8f21dfd2645b5058e3c875b0a57e7d49a4d59 Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Fri, 9 Mar 2018 22:27:26 -0600 Subject: [PATCH] Update Float ceil and floor to accept args --- vm/float.go | 73 ++++++++++++++++++++++++++++++++++++++++++------ vm/float_test.go | 30 ++++++++++++++++++-- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/vm/float.go b/vm/float.go index 13530161a..30661ac46 100644 --- a/vm/float.go +++ b/vm/float.go @@ -383,11 +383,36 @@ func builtinFloatInstanceMethods() []*BuiltinMethodObject { Name: "ceil", Fn: func(receiver Object, sourceLine int) builtinMethodBody { return func(t *thread, args []Object, blockFrame *normalCallFrame) Object { + if len(args) > 1 { + return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 1 integer arguements. got=%d", len(args)) + } + r := receiver.(*FloatObject) - result := math.Ceil(r.value) - newInt := t.vm.initIntegerObject(int(result)) - newInt.flag = i - return newInt + + if len(args) == 0 { + result := math.Ceil(r.value) + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + + p, ok := args[0].(*IntegerObject) + + if !ok { + return t.vm.initErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name) + } + + shift := math.Pow10(p.value) + shifted := r.value * shift + result := math.Ceil(shifted) / shift + + if p.value <= 0 { + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + + return t.vm.initFloatObject(result) } }, }, @@ -404,11 +429,35 @@ func builtinFloatInstanceMethods() []*BuiltinMethodObject { Name: "floor", Fn: func(receiver Object, sourceLine int) builtinMethodBody { return func(t *thread, args []Object, blockFrame *normalCallFrame) Object { + if len(args) > 1 { + return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 1 integer arguements. got=%d", len(args)) + } + r := receiver.(*FloatObject) - result := math.Floor(r.value) - newInt := t.vm.initIntegerObject(int(result)) - newInt.flag = i - return newInt + + if len(args) == 0 { + result := math.Floor(r.value) + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + + p, ok := args[0].(*IntegerObject) + + if !ok { + return t.vm.initErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name) + } + + shift := math.Pow(10, float64(p.value)) + shifted := r.value * shift + result := math.Floor(shifted) / shift + + if p.value <= 0 { + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + return t.vm.initFloatObject(result) } }, }, @@ -513,3 +562,11 @@ func (f *FloatObject) toJSON(t *thread) string { func (f *FloatObject) equal(e *FloatObject) bool { return f.value == e.value } + +// Math helper functions ------------------------------------------------ + +// Rounds a float64 to a given place in integers +func roundPlaces(f float64, places int) float64 { + shift := math.Pow(f, float64(places)) + return math.Floor(f+0.5) / shift +} diff --git a/vm/float_test.go b/vm/float_test.go index 306fa360e..48bd5b7c7 100644 --- a/vm/float_test.go +++ b/vm/float_test.go @@ -272,8 +272,8 @@ func TestFloatAbs(t *testing.T) { input string expected interface{} }{ - {"3.14.abs", 3.14}, - {"-1.23.abs", 1.23}, + {"34.56.abs", 34.56}, + {"-34.56.abs", 34.56}, } for i, tt := range tests { @@ -294,6 +294,19 @@ func TestFloatCeil(t *testing.T) { {"2.0.ceil", 2}, {"-1.2.ceil", -1}, {"-2.0.ceil", -2}, + {"1.234567.ceil(2)", 1.24}, + {"1.234567.ceil(3)", 1.235}, + {"1.234567.ceil(4)", 1.2346}, + {"1.234567.ceil(5)", 1.23457}, + {"34567.89.ceil(-5)", 99999}, // TODO: This is 100000 in Ruby + {"34567.89.ceil(-4)", 40000}, + {"34567.89.ceil(-3)", 35000}, + {"34567.89.ceil(-2)", 34600}, + {"34567.89.ceil(-1)", 34570}, + {"34567.89.ceil(0)", 34568}, + {"34567.89.ceil(1)", 34567.9}, + {"34567.89.ceil(2)", 34567.89}, + {"34567.89.ceil(3)", 34567.89}, } for i, tt := range tests { @@ -314,6 +327,19 @@ func TestFloatFloor(t *testing.T) { {"2.0.floor", 2}, {"-1.2.floor", -2}, {"-2.0.floor", -2}, + {"1.234567.floor(2)", 1.23}, + {"1.234567.floor(3)", 1.234}, + {"1.234567.floor(4)", 1.2345}, + {"1.234567.floor(5)", 1.23456}, + {"34567.89.floor(-5)", 0}, + {"34567.89.floor(-4)", 30000}, + {"34567.89.floor(-3)", 34000}, + {"34567.89.floor(-2)", 34500}, + {"34567.89.floor(-1)", 34560}, + {"34567.89.floor(0)", 34567}, + {"34567.89.floor(1)", 34567.8}, + {"34567.89.floor(2)", 34567.89}, + {"34567.89.floor(3)", 34567.89}, } for i, tt := range tests {