2021-12-07 16:09:17 +01:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2021-11-23 13:10:03 +01:00
|
|
|
module Rpl
|
2021-12-07 15:50:58 +01:00
|
|
|
module Lang
|
|
|
|
module Core
|
|
|
|
module_function
|
|
|
|
|
|
|
|
# addition
|
|
|
|
def add( stack )
|
|
|
|
addable = %i[numeric string name]
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [addable, addable] )
|
2021-12-07 15:50:58 +01:00
|
|
|
|
|
|
|
result = { type: case args[1][:type]
|
|
|
|
when :name
|
|
|
|
:name
|
|
|
|
when :string
|
2021-11-10 16:20:47 +01:00
|
|
|
:string
|
2021-12-07 15:50:58 +01:00
|
|
|
when :numeric
|
|
|
|
if args[0][:type] == :numeric
|
|
|
|
:numeric
|
|
|
|
else
|
|
|
|
:string
|
|
|
|
end
|
|
|
|
end }
|
|
|
|
|
|
|
|
args.each do |elt|
|
|
|
|
elt[:value] = elt[:value][1..-2] unless elt[:type] == :numeric
|
|
|
|
end
|
|
|
|
|
|
|
|
result[:value] = case result[:type]
|
|
|
|
when :name
|
|
|
|
"'#{args[1][:value]}#{args[0][:value]}'"
|
|
|
|
when :string
|
|
|
|
"\"#{args[1][:value]}#{args[0][:value]}\""
|
|
|
|
when :numeric
|
|
|
|
args[1][:value] + args[0][:value]
|
2021-11-10 16:20:47 +01:00
|
|
|
end
|
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
result[:base] = 10 if result[:type] == :numeric # TODO: what if operands have other bases ?
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << result
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# substraction
|
|
|
|
def subtract( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[1][:value] - args[0][:value] }
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# negation
|
|
|
|
def negate( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[0][:value] * -1 }
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# multiplication
|
|
|
|
def multiply( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[1][:value] * args[0][:value] }
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# division
|
|
|
|
def divide( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
raise 'Division by 0' if args[0][:value].zero?
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[1][:value] / args[0][:value] }
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# inverse
|
|
|
|
def inverse( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
raise 'Division by 0' if args[0][:value].zero?
|
2021-11-10 16:20:47 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: 1.0 / args[0][:value] }
|
|
|
|
end
|
2021-11-18 15:44:09 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# power
|
|
|
|
def power( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-11-18 15:44:09 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[1][:value]**args[0][:value] }
|
|
|
|
end
|
2021-11-18 15:58:59 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# rpn_square root
|
|
|
|
def sqrt( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-11-18 15:58:59 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
2021-12-07 16:19:23 +01:00
|
|
|
value: BigMath.sqrt( BigDecimal( args[0][:value] ), Rpl::Lang::Core.precision ) }
|
2021-12-07 15:50:58 +01:00
|
|
|
end
|
2021-11-18 15:58:59 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# rpn_square
|
|
|
|
def sq( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-11-18 15:58:59 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[0][:value] * args[0][:value] }
|
|
|
|
end
|
2021-11-18 15:58:59 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# absolute value
|
|
|
|
def abs( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-11-23 13:10:03 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: args[0][:value].abs }
|
|
|
|
end
|
2021-11-23 13:10:03 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# decimal representation
|
|
|
|
def dec( stack )
|
|
|
|
base( stack << { type: :numeric, base: 10, value: 10 } )
|
|
|
|
end
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# hexadecimal representation
|
|
|
|
def hex( stack )
|
|
|
|
base( stack << { type: :numeric, base: 10, value: 16 } )
|
|
|
|
end
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# binary representation
|
|
|
|
def bin( stack )
|
|
|
|
base( stack << { type: :numeric, base: 10, value: 2 } )
|
|
|
|
end
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# arbitrary base representation
|
|
|
|
def base( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
args[1][:base] = args[0][:value]
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
stack << args[1]
|
|
|
|
end
|
2021-11-23 16:16:21 +01:00
|
|
|
|
2021-12-07 15:50:58 +01:00
|
|
|
# 1 if number at stack level 1 is > 0, 0 if == 0, -1 if <= 0
|
|
|
|
def sign( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-12-07 15:50:58 +01:00
|
|
|
value = if args[0][:value].positive?
|
|
|
|
1
|
|
|
|
elsif args[0][:value].negative?
|
|
|
|
-1
|
|
|
|
else
|
|
|
|
0
|
|
|
|
end
|
|
|
|
|
|
|
|
stack << { type: :numeric, base: 10,
|
|
|
|
value: value }
|
|
|
|
end
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
# OPERATIONS ON REALS
|
|
|
|
|
|
|
|
# percent
|
|
|
|
def percent( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << { type: :numeric,
|
|
|
|
base: 10,
|
|
|
|
value: args[0][:value] * ( args[1][:value] / 100.0 ) }
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# inverse percent
|
|
|
|
def inverse_percent( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << { type: :numeric,
|
|
|
|
base: 10,
|
|
|
|
value: 100.0 * ( args[0][:value] / args[1][:value] ) }
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# modulo
|
|
|
|
def mod( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
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 )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << { type: :numeric,
|
|
|
|
base: 10,
|
|
|
|
value: Math.gamma( args[0][:value] ) }
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# largest number <=
|
|
|
|
def floor( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << { type: :numeric,
|
|
|
|
base: 10,
|
|
|
|
value: args[0][:value].floor }
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# smallest number >=
|
|
|
|
def ceil( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << { type: :numeric,
|
|
|
|
base: 10,
|
|
|
|
value: args[0][:value].ceil }
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# min of 2 real numbers
|
|
|
|
def min( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << ( args[0][:value] < args[1][:value] ? args[0] : args[1] )
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
|
|
|
|
|
|
|
# max of 2 real numbers
|
|
|
|
def max( stack )
|
2021-12-07 16:19:23 +01:00
|
|
|
stack, args = Rpl::Lang::Core.stack_extract( stack, [%i[numeric], %i[numeric]] )
|
2021-12-07 16:17:28 +01:00
|
|
|
|
|
|
|
stack << ( args[0][:value] > args[1][:value] ? args[0] : args[1] )
|
|
|
|
|
|
|
|
stack
|
|
|
|
end
|
2021-11-10 16:20:47 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|