You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 20:02:22