如何在Elixir中安全实现加密货币大、小单位互转?
Elixir中加密货币单位转换的稳妥实现方法
加密货币API涉及的超大数字转换核心是避免精度丢失,Elixir的任意精度整数特性天然适合处理大整数,而带小数的场景必须用Decimal库(而非Float)来保证精确性。以下是两种转换的具体实现:
1. 小单位转常规单位
小单位为整数,转换逻辑是除以10^decimals。需区分整除/非整除场景,整除时返回整数,非整除时返回Decimal类型保留精度。
实现代码
defmodule Crypto.UnitConverter do @spec small_to_regular(integer(), pos_integer()) :: {:ok, integer() | Decimal.t()} | {:error, String.t()} def small_to_regular(small_unit, decimals) when is_integer(small_unit) and is_integer(decimals) and decimals > 0 do divisor = :math.pow(10, decimals) |> round() remainder = rem(small_unit, divisor) result = if remainder == 0 do div(small_unit, divisor) else Decimal.new(small_unit) |> Decimal.div(Decimal.new(divisor)) end {:ok, result} end def small_to_regular(_, _) do {:error, "参数错误:small_unit必须是整数,decimals必须是正整数"} end end # 调用示例 Crypto.UnitConverter.small_to_regular(123000000000000000000, 18) # {:ok, 123} Crypto.UnitConverter.small_to_regular(123450000000000000000, 18) # {:ok, #Decimal<123.45>}
2. 常规单位转小单位
常规单位可能是整数、带小数的字符串或Decimal,必须用Decimal处理输入避免精度丢失,转换逻辑是乘以10^decimals后转整数(可选四舍五入)。
实现代码
defmodule Crypto.UnitConverter do # 接上上面的模块内容 @spec regular_to_small(integer() | String.t() | Decimal.t(), pos_integer()) :: {:ok, integer()} | {:error, String.t()} def regular_to_small(regular_unit, decimals) when is_integer(decimals) and decimals > 0 do with {:ok, decimal} <- Decimal.cast(regular_unit), multiplier <- :math.pow(10, decimals) |> round() |> Decimal.new(), product <- Decimal.mul(decimal, multiplier), rounded <- Decimal.round(product, 0), # 可选:四舍五入到整数 integer <- Decimal.to_integer(rounded) do {:ok, integer} else :error -> {:error, "常规单位输入无效"} _ -> {:error, "转换失败"} end end def regular_to_small(_, _) do {:error, "参数错误:decimals必须是正整数"} end end # 调用示例 Crypto.UnitConverter.regular_to_small(123, 18) # {:ok, 123000000000000000000} Crypto.UnitConverter.regular_to_small("123.45", 18) # {:ok, 123450000000000000000} Crypto.UnitConverter.regular_to_small(Decimal.new("123.456"), 18) # {:ok, 123456000000000000000}
核心注意事项
- 绝对避免使用Float:浮点数无法精确表示部分小数(如0.1),会导致转换精度丢失,所有带小数的场景必须用
Decimal。 - 利用Elixir整数特性:Elixir支持任意精度整数,超大数字运算不会出现溢出问题。
- 错误处理:通过模式匹配和
with语句处理非法输入,保证函数鲁棒性。
内容的提问来源于stack exchange,提问作者Kon
相关产品推荐
相关产品推荐

