NEXT社区小课堂 | 第十一课:NEO中数字的表达和运算

NEXT社区 | 小课堂html

因为近期NEXT社区加入不少新的小伙伴,有在校大学生,有对区块链感兴趣的传统企业从业者。为了更方便、更系统的让NEXT社区的伙伴们了解NEO的技术知识,所以咱们开设了小课堂,每周3节,向你们普及NEO相关的知识要点!git

 

NEXT社区小课堂 | 第十一课github

NEO中数字的表达和运算算法

 


 

计算的问题

 

一、区块链通常有代币,而代币互相转移必然会设计到计算数组

 

二、Neo中有GAS, 精确到小数点后8位,那么如何保障浮点数计算的正确网络

 

带着上面两个问题,尝试学习理解一下,一个带有激励机制的网络中,如何保证经济计算的正确。性能

 

 

Neo中数据的范围和精确度

 

一、NEO 的有 1 亿管理代币,NEO 的最小单位为 1,不可再分割。学习

 

二、GAS 是燃料代币,最大总量上限为 1 亿,用于实现对 NEO 网络使用时的资源控制。NEO 网络对代币转帐和智能合约的运行和存储进行收费,从而实现对记帐人的经济激励和防止资源滥用。GAS 的最小单位为 0.00000001。区块链

 

三、NEO和GAS的具体分发方法能够查看白皮书ui

http://docs.neo.org/zh-cn/index.html

 

四、因为GAS是小数,必须保证计算时四舍五入的正确性。

 

综上所述,NEO系统中数值的范围是:


NEO:0~100000000,精确度为1
GAS: 0.00000001~100000000.00000000

 

 

计算机中数值的表达

 

计算机系统通常来讲是对现实世界的模拟,用来运算一个现实中遇到的问题,那么现实世界和计算机系统通常就有一个映射关系

 

咱们现实世界中的各类数学概念中的数,在计算机中都要有一种表达方式。简单的描述一下我所认识到的计算机世界:

 

1、整型:

 

整数在C#中是int,long,ulong等类型,咱们看一下他的表示范围。

 

64位机器上C#类型 范围
int

Signed:

From −2,147,483,648 

to 2,147,483,647, 

from −(231) 

to 231 − 1

long

Signed:

From −9,223,372,036,854,775,808 

to 9,223,372,036,854,775,807, 

from −(263) 

to 263 − 1

 

在C#中,int的范围是正负20亿左右(十进制),long的范围是2的63次方=9223372036854775808,若是以米做单位,大约为光走一千年的距离;若是以秒做单位,大约为3000亿年,十进制是19位的一个数字。

 

因为Neo最大量是1亿,最小单位为1,在64位机器上作运算基本不会溢出,因此直接用long我以为也是能够的。

 

2、浮点型:

 

浮点(英语:floating point,缩写为FP)是一种对于实数的近似值数值表现法,由一个有效数字(即尾数)加上幂数来表示,一般是乘以某个基数的整数次指数获得。

 

以这种表示法表示的数值,称为浮点数(floating-point number)。利用浮点进行运算,称为浮点计算,这种运算一般伴随着由于没法精确表示而进行的近似或舍入。

 

在电脑使用的浮点数被电气电子工程师协会(IEEE)规范化为IEEE 754。

 

并非说小数叫作浮点数。准确的来讲:“浮点数”是一种表示数字的标准,整数也能够用浮点数的格式来存储。

 

在C#的程序语言中,浮点数用float和double来表示。

 

EEE 754 规定,浮点数的表示方法为:

 

浮点数表示方法

 

浮点数表示举例

 

 

整型和浮点型都是64位的状况下,浮点型表示的范围更大,可是虽然范围打,能够表示的数字的数量,确实根据表示数的二进制位肯定的。

 

3、decimal型:

 

decimal

 

从上表能够看出,decimal的有效位数很大,达到了28位,可是表示的数据范围却比float和double类型小。decimal类型并非C#中的基础类型,因此使用的时候会对计算时的性能有影响。

 

因为精度高,更适合用来处理金融系统的计算问题。可是其自己计算仍是有偏差的,精度再高都是实数轴上的离散点。

 

4、类型的比较:

 

TYPE APPROXIMATE RANGE PRECISION .NET FRAMEWORK TYPE
double

±5.0 × 10−324

to 

±1.7 × 10308

15-16 

digits

System.Double

float

-3.4 × 1038

to 

+3.4 × 1038

7 digits

System.Single

decimal

(-7.9 x 1028

to 7.9 x 1028)

 / (100 to 1028)

28-29 

significant 

digits

System.Decimal

 

 

TYPE RANGE SIZE .NET FRAMEWORK TYPE
int

-2,147,483,648

to 

2,147,483,647

Signed 

32-bit 

integer

System.

Int32

uint

0

to 

4,294,967,295

Unsigned 

32-bit 

integer

System.

UInt32

long

-9,223,372,036,854,775,808

to 

9,223,372,036,854,775,807

Signed 

64-bit 

integer

System.

Int64

ulong

0

to 

18,446,744,073,709,551,615

Unsigned

64-bit 

integer

System.

UInt64

sbyte -128 to 127

Signed

8-bit 

integer

System.

SByte

short

-32,768

to 

32,767

Signed

16-bit 

integer

System.

Int16


 

 

范围,精度,准确性

 

为了更进一步的讨论计算机中的数字,咱们须要搞清楚范围,精度,准确性这三个概念。

 

数的范围是在数的当前表示格式下,最小的值到最大值中间的间隔。好比16位有符号的整数范围是-32768 to 32767,超过范围的就不能表示。

 

须要注意的是,在范围内的有些数,在当前格式下也不能表示,好比整型就无法表示小数。因此每种类型都只能表达实数轴上离散的点。

 

精度和准确性一般让人混淆,这是两个彻底不一样的概念。精度是“表示数的格式”的一种属性,1.3333精确到小数点后四位,1.333300精确到小数点后6位,但他们是同一个值。

 

可是1.333300的下一个数是1.333301,1.3333的下一个数是1.3334,可见高精度能够表示同一个范围内更多的数。

 

精度会影响到运算结果,因此在系统中须要特别注意这些问题:

Using one digit precision:
0.4 * 0.6 + 0.6 * 0.4

= 0.24 + 0.24 Calculate products
= 0.2 + 0.2 Round to 1 digit
= 0.4 Final result


Using two digit precision:
0.4 * 0.6 + 0.6 * 0.4

= 0.24 + 0.24 Calculate products
= 0.24 + 0.24 Keep the 2 digits
= 0.48 Calculate sum
= 0.5 Round to 1 digit

准确性须要在使用的上下文中讨论,表示运算的结果和真实的值之间的差别的大小,准确性和错误相关,高准确性意味着小的偏差。

准确性和精度是相关的,可是并非直接相关,低精度在有些场景中,也是准确的,好比:

Byte n0 = 0x03;
Int16 n1 = 0x0003;
Int32 n2 = 0x00000003;
Single n3 = 3.000000f;
Double n4 = 3.000000000000000;

 

每种格式都准确表达了3,可是这些变量的精度是不一样的,使用的位数也不同,从8到64位。

 

 

舍入偏差

 

假定你要在系统中使用pi,你会发现无论用任何类型的变量,你都没法准确表达它,你的计算必然包含着偏差,你只能选择一个近似于pi的数去运算。你使用的不是pi,而是pi+e,假定e为舍入偏差。

更不爽的是,你的给个运算都会带来新的偏差,好比你须要计算(a+b),假定a,b和pi同样是无理数,那么实际上你计算的是(a + b) + (Ea + Eb + Esum)。

咱们必须找到一种方法减小偏差,使咱们的结果能够反馈出实际的状况。

 

能够看两个由于计算不许确致使的事故:

·  1990年2月25日,海湾战争期间,在沙特阿拉伯宰赫兰的爱国者导弹防护系统因浮点数舍入错误而失效,该系统的计算机精度仅有24位,存在0.0001%的计时偏差,因此有效时间阙值是20个小时。当系统运行100个小时之后,已经积累了0.3422秒的偏差。这个错误致使导弹系统不断地自我循环,而不能正确地瞄准目标。结果未能拦截一枚伊拉克飞毛腿导弹,飞毛腿导弹在军营中爆炸,形成28名美国陆军死亡。

·  1996年6月4日,在亚利安五号运载火箭发射后37秒,偏离预约轨道而炸毁。缘由是软件系统试图将64位浮点数转换为16位浮点数,形成溢出错误。

·  温哥华证券交易所曾开发了一项股票指数。当其在1982年推出时,指数的值是1000.000。在后来的从新计算时屡次运用舍入到小数点后三位的操做。22个月之后,指数的值是524.881,然而事实上应该是1009.811。

 

 

如何解决舍入偏差

一、https://en.wikipedia.org/wiki/Kahan_summation_algorithm

二、使用更高精度的类型,具体问题具体分析

 

 

 

选择在Neo中处理数据的类型

 

neon钱包

 

一、Neo使用long来运算,精度没有问题,范围在普通的加减乘除状况下也很难溢出。咱们能够看到1亿相乘也不会超过范围,可是继续相乘就会溢出了,可是不太可能有这种累加的效果,只须要代码中注意就好。

 

运算 大小
long.max 9223372036854775807
1亿*1亿 10000000000000000
 

 

二、Gas的运算须要精确到小数点后8位

 

咱们假定支持最大的数字相乘而不溢出就是知足运算的范围要求,那么整数位须要1016,尾数位须要10-16


Double类型在范围和精度上都知足要求
decimal在范围和精度上知足要求

 

如今虽然已经给Neo选择好类型,可是咱们进入代码,会发现Neo使用了一个叫Fixed8的类型表示数据,因此咱们进一步讨论。

 

 

定点数

 

简单的来讲,定点数就是小数点在特定位置的数,好比Neo中的fixed8就是始终保持小数点后8位。

 

定义一个定点数,须要包含两部分:

 

一、有多少位

二、小数点在哪里

 

定点数实际上使用整型表达就能够了,咱们只须要另外保存一下精度,好比Fixed8就是把long型除以100000000。下图显示了定点数的格式

 

定点数如何保存

 

 

定点数的优缺点

 

一、因为使用整型保存,全部的计算方法其实和整型相似

 

二、相同二进制位数下,与整型相比,表示的范围缩小了,由于精度提升了,也能够把整型当作精度为1的定点数。

 

三、与浮点数相比,定点数运算速度更快。

 

 

 

fixed8中的一个bug

 

在看源码的时候,发现fixed8的乘法是使用位移方法本身实现的,结果发现其准确性并无两个decimal相乘高,虽然如此小的偏差不必定会给系统带来什么影响,可是仍是一个有趣的发现。
https://github.com/neo-project/neo/issues/194

 

 

 

极大的数

 

若是数字的范围和精度都极大,那么就须要特殊处理,Neo中使用了BigInteger封装了一个BigDecimal的结构体。BigInteger二的地方是不支持小数,因此Neo中的小数必须乘以一个精度转成BigDecimal,BigDecimal只是保存了一下精度。

 

 

 

UInt256, UInt160

 

在Neo中发现还有两个基于byte的数据类型UInt256,UInt160。这两个主要用来保存hash算法的的值。

 

UInt256有32的字节大小,256个bit,用来保存"22c199231f06e2091f89e0128e7d875fdfb0fb5fc7c4f916af0c50d04ab70e74"这样的字符串。这个字符串是64个字符组成的,而64位机器上,char类型是2个字节,为何用32位就能够表示呢?咱们看看下面代码。

public static byte[] HexToBytes(this string value){if (value == null || value.Length == 0)return new byte[0];if (value.Length % 2 == 1)throw new FormatException();byte[] result = new byte[value.Length / 2];for (int i = 0; i < result.Length; i++)result[i] = byte.Parse(value.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier);return result;}

 

 

这段代码表示把以字符串表示的的16进制的数转成byte数组。因此只要hash的目标集合在0~f之间就能够。
 

咱们能够看到"22c199231f06e2091f89e0128e7d875fdfb0fb5fc7c4f916af0c50d04ab70e74"就在这个范围,若是你改一下,好比加个z进去,就会抛出异常了。

 

 

 

总结

 

上面只是简单的介绍,基本上是很容易理解的,可是实际上数的表示和运算是一个很是基础的问题,越简单的问题每每包含着很复杂的原理.

 

 

本文来源:https://www.jianshu.com/p/ac337d1869ec

 

 

  联系咱们  

微博:https://weibo.com/u/6724929880

官网:https://neonext.club/

QQ群:612334080

电报:https://t.me/neonextop

twitter:https://twitter.com/NE0NEXT

 

扫码关注NEO NEXT官方公众号

获取更多一手社区资讯

相关文章
相关标签/搜索