IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 如何在 sCrypt 合约中实现浮点数运算 -> 正文阅读

[区块链]如何在 sCrypt 合约中实现浮点数运算

相信很多开发者朋友在使用 sCrypt 开发比特币智能合约时,会有这样一个问题:为什么没有浮点数的数据类型?比如 Float 或者 Double?这篇文章我们就来聊聊在合约中如何实现模拟浮点数的高精度计算。

常见的编程语言一般都会有原生的浮点数支持,大部分都会参考实现 IEEE754 标准,但包括比特币在内的很多区块链的智能合约都没有原生支持浮点数,这其中可能有两个重要原因:1. 如果使用基于 FPU 硬件的实现(hard float)可能会有不同架构的节点在验证单笔交易时产生不同结果,从而导致共识失败;2. 如果使用基于软件模拟的实现(soft float)则执行效率会比较低,也可能有精度问题。

那么如果我们需要在合约内使用基于浮点数的高精度计算时应该怎么做呢?这里我们介绍两种可行的方法供大家参考。

一种基于定点数的实现

一个最简单直接的方法就是将其转换为整数运算问题,如直接乘以一个10的 n 次方(这里的 n 等于需要小数点后的精度)。这种方法的优点是实现简单且成本低;缺点是如果有计算会产生分步的中间结果时,会有累计的精度损失误差。这里我们实现了一个基于定点数的库合约

struct FP {
  int val; // scaled-up value depends on precison.
}

// 
library FixedPoint {
  int precision; // should be 10^n

  function add(FP x, FP y) : FP {
    return {x.val + y.val};
  }

  function sub(FP x, FP y) : FP {
    return {x.val - y.val};
  }

  function mul(FP x, FP y) : FP {
    return {x.val * y.val / this.precision};
  }

  function div(FP x, FP y) : FP {
    return {x.val * this.precision / y.val};
  }

  function abs(FP x) : FP {
    return {abs(x.val)};
  }

  function fromInt(int i) : FP {
    return {i * this.precision};
  }

  function toInt(FP fp) : int {
    return fp.val / this.precision;
  }

}

以下是它的使用示例合约

import "fixedPoint.scrypt";

contract Test {
  public function unlock(int precision, int x, int y, int op, int r) {
    FixedPoint fp = new FixedPoint(precision);
    FP result = fp.fromInt(0);
    FP fpX = {x};
    FP fpY = {y};
    if (op == 0) {
      result = fp.add(fpX, fpY);
    } else if (op == 1) {
      result = fp.sub(fpX, fpY);
    } else if (op == 2) {
      result = fp.mul(fpX, fpY);
    } else if (op == 3) {
      result = fp.div(fpX, fpY);
    } else if (op == 4) {
      result = fp.abs(fpX);
    }
    require(result == {r});
    require(fp.toInt(result) == r / precision);
  }
}

一种基于分数的实现

另外一种方法利用了比特币智能合约中的整数为非固定位大整数这一特点,实现了一种基于分数的高精度计算,即将所有运算因子都保存为分数形式。这样的优点是哪怕有中间结果也无需担心精度损失,因为舍尾操作可以只在最后进行;缺点是实现和使用成本较前一种高一些。下面是我们实现的一个库合约

struct Fraction {
  int n; // numerator
  int d; // denominator
}

// A fraction-based math library for high precision calculation.
library FRMath {
  
  static function add(Fraction x, Fraction y) : Fraction {
    return {
      x.n * y.d + y.n * x.d,
      x.d * y.d
    };
  }

  // safe add, requires both argument denominators > 0
  static function sAdd(Fraction x, Fraction y) : Fraction {
    require(x.d > 0 && y.d > 0);
    return {
      x.n * y.d + y.n * x.d,
      x.d * y.d
    };
  }

  static function sub(Fraction x, Fraction y) : Fraction {
    return {
      x.n * y.d - y.n * x.d,
      x.d * y.d
    };
  }

  // safe sub, requires both argument denominators > 0
  static function sSub(Fraction x, Fraction y) : Fraction {
    require(x.d > 0 && y.d > 0);
    return {
      x.n * y.d - y.n * x.d,
      x.d * y.d
    };
  }

  static function mul(Fraction x, Fraction y) : Fraction {
    return {
      x.n * y.n,
      x.d * y.d
    };
  }

  // safe mul, requires both argument denominators > 0
  static function sMul(Fraction x, Fraction y) : Fraction {
    require(x.d > 0 && y.d > 0);
    return {
      x.n * y.n,
      x.d * y.d
    };
  }

  static function div(Fraction x, Fraction y) : Fraction {
    return {
      x.n * y.d,
      x.d * y.n
    };
  }

  // safe div, requires both argument denominators > 0 and y != 0
  static function sDiv(Fraction x, Fraction y) : Fraction {
    require(x.d > 0 && y.d > 0 && y.n != 0);
    return {
      x.n * y.d,
      x.d * y.n
    };
  }

  static function abs(Fraction x) : Fraction {
    return {
      abs(x.n),
      abs(x.d)
    };
  }

  // safe abs, requires both argument denominators > 0
  static function sAbs(Fraction x) : Fraction {
    require(x.d > 0);
    return {
      abs(x.n),
      x.d
    };
  }

  static function equal(Fraction x, Fraction y) : bool {
    return sub(x, y).n == 0;
  }

  static function sEqual(Fraction x, Fraction y) : bool {
    return sSub(x, y).n == 0;
  }

  static function toInt(Fraction x) : int {
    return x.n / x.d;
  }

  static function fromInt(int numerator, int denominator) : Fraction {
    return {numerator, denominator};
  }

  static function scaleUp(Fraction x, int s) : int {
    return x.n * s / x.d;
  }
}

已经使用它的示例合约

import "fractionMath.scrypt";

contract Main {

  function runOp(int op, Fraction x, Fraction y) : Fraction {
    Fraction r = {0, 1};
    if (op == 0) {
      r = FRMath.add(x, y);
    } else if(op == 1) {
      r = FRMath.sub(x, y);
    } else if(op == 2) {
      r = FRMath.mul(x, y);
    } else if(op == 3) {
      r = FRMath.div(x, y);
    } else if(op == 4) {
      r = FRMath.abs(x);
    }
    return r;
  }

  function runSafeOp(int op, Fraction x, Fraction y) : Fraction {
    Fraction r = {0, 1};
    if (op == 0) {
      r = FRMath.sAdd(x, y);
    } else if(op == 1) {
      r = FRMath.sSub(x, y);
    } else if(op == 2) {
      r = FRMath.sMul(x, y);
    } else if(op == 3) {
      r = FRMath.sDiv(x, y);
    } else if(op == 4) {
      r = FRMath.sAbs(x);
    }
    return r;
  }

  public function unlock(Fraction x, Fraction y, Fraction z, int op, bool strict) {
    Fraction r = {0, 1};
    if (strict) {
      r = this.runSafeOp(op, x, y);
      require(FRMath.sEqual(r, z));
    } else {
      r = this.runOp(op, x, y);
      require(FRMath.equal(r, z));
    }
    require(true);
  }

  public function unlockScaled(int s, Fraction x, Fraction y, int op, bool strict, int sr) {
    Fraction r = {0, 1};
    if (strict) {
      r = this.runSafeOp(op, x, y);
      require(FRMath.scaleUp(r, s) == sr);
    } else {
      r = this.runOp(op, x, y);
      require(FRMath.scaleUp(r, s) == sr);
    }
    require(true);
  }
}

总结

上面是我们针对合约内使用浮点数的需求提供的两种实现参考,希望对各位有所帮助。如果有进一步的需求和改进方案,也欢迎和我们进一步交流或提供代码 PR,再次感谢。

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:14:28  更:2021-07-15 16:14:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:32:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码