Floating point 如何在Erlang中检查浮点是否为整数?

Floating point 如何在Erlang中检查浮点是否为整数?,floating-point,integer,erlang,Floating Point,Integer,Erlang,我正在学习Erlang,作为在反向波兰符号计算器中实现阶乘函数的练习。到目前为止,我有: -module(rps). -export([calculate/1]). calculate(List) -> calculate(List, []). calculate([], [ Number ]) -> Number; calculate([ Head | Tail ], Stack) -> case Head of "+" -> [ B

我正在学习Erlang,作为在反向波兰符号计算器中实现阶乘函数的练习。到目前为止,我有:

-module(rps).
-export([calculate/1]).

calculate(List) ->
  calculate(List, []).

calculate([], [ Number ]) ->
  Number;
calculate([ Head | Tail ], Stack) ->
  case Head of
    "+" ->
      [ B, A | Rest ] = Stack,
      calculate(Tail, [ A + B | Rest ]);
    "-" ->
      [ B, A | Rest ] = Stack,
      calculate(Tail, [ A - B | Rest ]);
    "*" ->
      [ B, A | Rest ] = Stack,
      calculate(Tail, [ A * B | Rest ]);
    "/" ->
      [ B, A | Rest ] = Stack,
      calculate(Tail, [ A / B | Rest ]);
    "!" ->
      [ A | Rest ] = Stack,
      calculate(Tail, [ factorial(A) | Rest ]);
    _ ->
      calculate(Tail, [ Head | Stack ])
  end.

factorial(N) ->
  factorial(N, 1).

factorial(0, Accumulator) ->
  Accumulator;
factorial(N, Accumulator) when N >= 0  ->
  factorial(N - 1, Accumulator * N).
现在问题出在我的阶乘/2函数中,特别是
N=0的基本情况。只要堆栈上的第一个元素是整数,它就可以正常工作,例如:

5> rpcalc:calculate([1, 2, "+", "!"]).
6
但是我注意到除法总是返回一个浮点,即使两个参数都是整数并且结果是整数,例如:

7> 4 / 2.
2.0
所以有时候浮动会出现在我的堆栈上。然后,即使它们是正数和整数,我的阶乘也会失败,因为
0.0=/=0
。其效果是:

13> rpcalc:calculate([6, 2, "/", "!"]).
** exception error: no function clause matching rpcalc:factorial(-1.0,0.0) (rpcalc.erl, line 33)
     in function  rpcalc:calculate/2 (rpcalc.erl, line 25)

在这里,支持正整数浮动的最优雅的方式是什么?我的直觉是在
factorial/1
中有一个案例,可以检测出这样的数字并将它们转换成整数,但也许有更好的方法?

存在
div
,它接受整数并执行整数除法。你可以这样写:

calculate([], [ Number ]) ->
    Number;
calculate([ "+" | Tail ], [ B, A | Rest ]) ->
    calculate(Tail, [ A + B | Rest ]);
calculate([ "-" | Tail ], [ B, A | Rest ]) ->
    calculate(Tail, [ A - B | Rest ]);
calculate([ "*" | Tail ], [ B, A | Rest ]) ->
    calculate(Tail, [ A * B | Rest ]);
calculate([ "/" | Tail ], [ B, A | Rest ])
    when is_integer(A), is_integer(B), A rem B =:= 0 ->
    calculate(Tail, [ A div B | Rest ]);
calculate([ "/" | Tail ], [ B, A | Rest ]) ->
    calculate(Tail, [ A / B | Rest ]);
calculate([ "!" | Tail ], [ A | Rest ]) ->
    calculate(Tail, [ factorial(A) | Rest ]);
calculate([ Head | Tail ], Stack) ->
    calculate(Tail, [ Head | Stack ]).

经过深思熟虑,以下是我自己的看法:

factorial(N) ->
  factorial(float_to_integer(N), 1).

factorial(0, Accumulator) ->
  Accumulator;
factorial(N, Accumulator) when N >= 0  ->
  factorial(N - 1, Accumulator * N).

float_to_integer(N) when is_integer(N) ->
  N;
float_to_integer(N) when is_float(N) ->
  Integer = trunc(N),
  case N == Integer of
    true ->
      Integer;
    false ->
      error(badarg)
  end.

我添加了一个名为
float\u to\u integer
的帮助程序,它返回一个整数作为任何整数,否则会抛出一个错误。这个名字有点误导人,因为它也可以处理整数。然后我用它来保护factorial/1,如果你使用区域整数,那么你可以使用相应的运算,在这个例子中是-div。所以
“/”->[B,A | Rest]=Stack,calculate(Tail,[A div B | Rest])。谢谢。这可能是解决方案的一部分,但问题是它总是会截断结果。我确实希望在一般情况下支持浮动,对于分数,我希望我的阶乘抛出。我只想要
3.0
生成
6
。谢谢。我做了一个小编辑,因为您的原始代码导致编译错误(
rpcalc.erl:20:变量“a”是未绑定的rpcalc.erl:20:变量“B”是未绑定的错误
)。此外,在某些情况下,它确实有助于防止除法产生的浮动,但是`rpcalc:calculate([2.0,2,“+”,“!”])又如何呢?@TadeuszŁazurski,只需添加几个条件。例如
“/”->[B,A | Rest]=堆栈,如果是|整数(A),则是|整数(B),A rem B=:=0->计算(Tail[A div B | Rest]);A==trunc(A),B==trunc(B)->计算(Tail[trunc(A)div trunc(B)| Rest]);真->计算(尾,[A/B | Rest])结束@Atomic_alarm我认为试图阻止除法返回浮动不是最好的方法。如果我增加更多的操作,我也必须保护它们。此外,浮动可能来自
calculate/1
的原始输入。请看一看我自己的答案,让我知道你的想法。@TadeuszŁazurski:这个错误是由你的代码的非爱尔兰性质引起的。请看我的更正。这是惯用的Erlang。@TadeuszŁazurski非整数有阶乘函数。它们是Gamma函数和Pi函数。好的解决方案,但最好使用模式匹配和比较。结果
float\u to\u integer(N),当是\u integer(N)->N时;float_to_integer(N)->integer=trunc(N),案例N==true的整数->整数;false->error(badarg)end.
Btw,如果您需要检查代码是否有效,您可以在上提问。谢谢@Atomic_alarm。我已经根据您的建议更新了代码示例。