diff --git a/lib/core.rb b/lib/core.rb index bed21b5..044ad11 100644 --- a/lib/core.rb +++ b/lib/core.rb @@ -9,6 +9,8 @@ require_relative './language/stack' require_relative './language/string' require_relative './language/test' require_relative './language/time-date' +require_relative './language/trig' +require_relative './language/logs' module Rpl module Core diff --git a/lib/dictionary.rb b/lib/dictionary.rb index 52914cc..3526fbf 100644 --- a/lib/dictionary.rb +++ b/lib/dictionary.rb @@ -50,18 +50,18 @@ module Rpl add( 'sign', proc { |stack| Rpl::Core.sign( stack ) } ) # OPERATIONS ON REALS - add( '%', proc { |stack| Rpl::Core.__todo( stack ) } ) # percent - add( '%CH', proc { |stack| Rpl::Core.__todo( stack ) } ) # inverse percent - add( 'mod', proc { |stack| Rpl::Core.__todo( stack ) } ) # modulo - add( 'fact', proc { |stack| Rpl::Core.__todo( stack ) } ) # n! for integer n or Gamma(x+1) for fractional x + add( '%', proc { |stack| Rpl::Core.percent( stack ) } ) + add( '%CH', proc { |stack| Rpl::Core.inverse_percent( stack ) } ) + add( 'mod', proc { |stack| Rpl::Core.mod( stack ) } ) + add( 'fact', proc { |stack| Rpl::Core.fact( stack ) } ) add( 'mant', proc { |stack| Rpl::Core.__todo( stack ) } ) # mantissa of a real number add( 'xpon', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponant of a real number - add( 'floor', proc { |stack| Rpl::Core.__todo( stack ) } ) # largest number <= - add( 'ceil', proc { |stack| Rpl::Core.__todo( stack ) } ) # smallest number >= + add( 'floor', proc { |stack| Rpl::Core.floor( stack ) } ) + add( 'ceil', proc { |stack| Rpl::Core.ceil( stack ) } ) add( 'ip', proc { |stack| Rpl::Core.__todo( stack ) } ) # integer part add( 'fp', proc { |stack| Rpl::Core.__todo( stack ) } ) # fractional part - add( 'min', proc { |stack| Rpl::Core.__todo( stack ) } ) # min of 2 real numbers - add( 'max', proc { |stack| Rpl::Core.__todo( stack ) } ) # max of 2 real numbers + add( 'min', proc { |stack| Rpl::Core.min( stack ) } ) + add( 'max', proc { |stack| Rpl::Core.max( stack ) } ) # OPERATIONS ON COMPLEXES add( 're', proc { |stack| Rpl::Core.__todo( stack ) } ) # complex real part @@ -133,7 +133,7 @@ module Rpl # STORE add( 'sto', proc { |stack| Rpl::Core.__todo( stack ) } ) # store a variable. ex: 1 'name' sto - add( '▶', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias + add( '▶', proc { |stack| Rpl::Core.sto( stack ) } ) # alias add( 'rcl', proc { |stack| Rpl::Core.__todo( stack ) } ) # recall a variable. ex: 'name' rcl add( 'purge', proc { |stack| Rpl::Core.__todo( stack ) } ) # delete a variable. ex: 'name' purge add( 'vars', proc { |stack| Rpl::Core.__todo( stack ) } ) # list all variables @@ -152,7 +152,8 @@ module Rpl add( '→', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias # TRIG ON REALS AND COMPLEXES - add( 'pi', proc { |stack| Rpl::Core.__todo( stack ) } ) # pi constant + add( 'pi', proc { |stack| Rpl::Core.pi( stack ) } ) + add( '𝛑', proc { |stack| Rpl::Core.pi( stack ) } ) # alias add( 'sin', proc { |stack| Rpl::Core.__todo( stack ) } ) # sinus add( 'asin', proc { |stack| Rpl::Core.__todo( stack ) } ) # arg sinus add( 'cos', proc { |stack| Rpl::Core.__todo( stack ) } ) # cosinus @@ -165,7 +166,8 @@ module Rpl add( 'r→d', proc { |stack| Rpl::Core.__todo( stack ) } ) # alias # LOGS ON REALS AND COMPLEXES - add( 'e', proc { |stack| Rpl::Core.__todo( stack ) } ) # Euler constant + add( 'e', proc { |stack| Rpl::Core.e( stack ) } ) + add( 'ℇ', proc { |stack| Rpl::Core.e( stack ) } ) # alias add( 'ln', proc { |stack| Rpl::Core.__todo( stack ) } ) # logarithm base e add( 'lnp1', proc { |stack| Rpl::Core.__todo( stack ) } ) # ln(1+x) which is useful when x is close to 0 add( 'exp', proc { |stack| Rpl::Core.__todo( stack ) } ) # exponential diff --git a/lib/language/logs.rb b/lib/language/logs.rb new file mode 100644 index 0000000..f54c92f --- /dev/null +++ b/lib/language/logs.rb @@ -0,0 +1,13 @@ +module Rpl + module Core + module_function + + # Euler constant + def e( stack ) + stack << { type: :numeric, + base: 10, + value: BigMath.E( Rpl::Core.precision ) } + stack + end + end +end diff --git a/lib/language/operations.rb b/lib/language/operations.rb index b67ef72..02bc87a 100644 --- a/lib/language/operations.rb +++ b/lib/language/operations.rb @@ -152,5 +152,91 @@ module Rpl stack << { type: :numeric, base: 10, value: value } end + + # OPERATIONS ON REALS + + # percent + def percent( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: args[0][:value] * ( args[1][:value] / 100.0 ) } + + stack + end + + # inverse percent + def inverse_percent( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: 100.0 * ( args[0][:value] / args[1][:value] ) } + + stack + end + + # modulo + def mod( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: args[1][:value] % args[0][:value] } + + stack + end + + # n! for integer n or Gamma(x+1) for fractional x + def fact( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: Math.gamma( args[0][:value] ) } + + stack + end + + # largest number <= + def floor( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: args[0][:value].floor } + + stack + end + + # smallest number >= + def ceil( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric]] ) + + stack << { type: :numeric, + base: 10, + value: args[0][:value].ceil } + + stack + end + + # min of 2 real numbers + def min( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + + stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] ) + + stack + end + + # max of 2 real numbers + def max( stack ) + stack, args = Rpl::Core.stack_extract( stack, [%i[numeric], %i[numeric]] ) + + stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] ) + + stack + end end end diff --git a/lib/language/trig.rb b/lib/language/trig.rb new file mode 100644 index 0000000..123747c --- /dev/null +++ b/lib/language/trig.rb @@ -0,0 +1,13 @@ +module Rpl + module Core + module_function + + # pi constant + def pi( stack ) + stack << { type: :numeric, + base: 10, + value: BigMath.PI( Rpl::Core.precision ) } + stack + end + end +end diff --git a/spec/language_operations_spec.rb b/spec/language_operations_spec.rb index 0f2eeb5..9ac9ea4 100644 --- a/spec/language_operations_spec.rb +++ b/spec/language_operations_spec.rb @@ -177,4 +177,77 @@ class TesttLanguageOperations < Test::Unit::TestCase assert_equal [{ value: 0, type: :numeric, base: 10 }], stack end + + def test_percent + stack = Rpl::Core.percent [{ value: 2, type: :numeric, base: 10 }, + { value: 33, type: :numeric, base: 10 }] + + assert_equal [{ value: 0.66, type: :numeric, base: 10 }], + stack + end + + def test_inverse_percent + stack = Rpl::Core.inverse_percent [{ value: 2, type: :numeric, base: 10 }, + { value: 0.66, type: :numeric, base: 10 }] + + assert_equal [{ value: 33, type: :numeric, base: 10 }], + stack + end + + def test_mod + stack = Rpl::Core.mod [{ value: 9, type: :numeric, base: 10 }, + { value: 4, type: :numeric, base: 10 }] + + assert_equal [{ value: 1, type: :numeric, base: 10 }], + stack + end + + def test_fact + stack = Rpl::Core.fact [{ value: 5, type: :numeric, base: 10 }] + + assert_equal [{ value: 24, type: :numeric, base: 10 }], + stack + end + + def test_floor + stack = Rpl::Core.floor [{ value: 5.23, type: :numeric, base: 10 }] + + assert_equal [{ value: 5, type: :numeric, base: 10 }], + stack + end + + def test_ceil + stack = Rpl::Core.ceil [{ value: 5.23, type: :numeric, base: 10 }] + + assert_equal [{ value: 6, type: :numeric, base: 10 }], + stack + end + + def test_min + stack = Rpl::Core.min [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] + + assert_equal [{ value: 1, type: :numeric, base: 10 }], + stack + + stack = Rpl::Core.min [{ value: 2, type: :numeric, base: 10 }, + { value: 1, type: :numeric, base: 10 }] + + assert_equal [{ value: 1, type: :numeric, base: 10 }], + stack + end + + def test_max + stack = Rpl::Core.max [{ value: 1, type: :numeric, base: 10 }, + { value: 2, type: :numeric, base: 10 }] + + assert_equal [{ value: 2, type: :numeric, base: 10 }], + stack + + stack = Rpl::Core.max [{ value: 2, type: :numeric, base: 10 }, + { value: 1, type: :numeric, base: 10 }] + + assert_equal [{ value: 2, type: :numeric, base: 10 }], + stack + end end