AFix
描述
AFix
是一个支持自动范围的定点类型,它在执行定点运算时跟踪可表示值的范围。
警告:此代码的大部分仍在开发中。 API 和函数原型可能会发生变化。
感谢用户反馈!
声明
AFix 可以在创建时指定总位宽或指数部分位宽:
AFix.U(12 bits) // U12.0
AFix(QFormat(12, 0, false)) // U12.0
AFix.UQ(8 bits, 4 bits) // U8.4
AFix.U(8 exp, 12 bits) // U8.4
AFix.U(8 exp, -4 exp) // U8.4
AFix.U(8 exp, 4 exp) // U8.-4
AFix(QFormat(12, 4, false)) // U8.4
AFix.S(12 bits) // S11.0 + sign
AFix(QFormat(12, 0, true)) // S11.0 + sign
AFix.SQ(8 bits, 4 bits) // S8.4 + sign
AFix.S(8 exp, 12 bits) // S8.3 + sign
AFix.S(8 exp, -4 exp) // S8.4 + sign
AFix(QFormat(12, 4, true)) // S7.4 + sign
这些将占据所有位的可表示范围。
例如:
AFix.U(12 bits)
可表示的范围是 0 to 4095。
AFix.SQ(8 bits, 4 bits)
的范围为 -4096 (-256) 到 4095 (255.9375)
AFix.U(8 exp, 4 exp)
的范围为 0 到 256
可以通过直接实例化类来创建自定义范围 AFix
值。
class AFix(val maxValue: BigInt, val minValue: BigInt, val exp: ExpNumber)
new AFix(4096, 0, 0 exp) // [0 to 4096, 2^0]
new AFix(256, -256, -2 exp) // [-256 to 256, 2^-2]
new AFix(16, 8, 2 exp) // [8 to 16, 2^2]
在定点数表示法中, maxValue
和 minValue
变量用于存储可表示的最大和最小整数值。这些数值是在进行 ``2^exp``(即2的exp次方)的乘法运算后得到的定点数的实际值。
AFix.U(2 exp, -1 exp)
可以表示:0, 0.5, 1.0, 1.5, 2, 2.5, 3, 3.5
AFix.S(2 exp, -2 exp)
可以表示:-2.0, -1.75, -1.5, -1.25, -1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75
指数值大于 0 是允许的,用来表示该数值大于 1 。
AFix.S(2 exp, 1 exp)
可以表示:-4, 2, 0, 2
AFix(8, 16, 2 exp)
可以表示:32, 36, 40, 44, 48, 52, 56, 60, 64
注意:AFix
将使用 5 位来保存此类型,因此它可以存储 16
,即它的 maxValue
。
数学运算
AFix
在硬件级别支持加法 (+
)、减法 (-
) 和乘法 (*
)。也提供了除法(\
)和模(%
)运算符,但这些不建议用硬件实现。
对 AFix
执行运算就像常规 Int
整型数一样。有符号数和无符号数是可以互操作的。有符号值和无符号值之间没有类型差异。
// Integer and fractional expansion
val a = AFix.U(4 bits) // [ 0 ( 0.) to 15 (15. )] 4 bits, 2^0
val b = AFix.UQ(2 bits, 2 bits) // [ 0 ( 0.) to 15 ( 3.75)] 4 bits, 2^-2
val c = a + b // [ 0 ( 0.) to 77 (19.25)] 7 bits, 2^-2
val d = new AFix(-4, 8, -2 exp) // [- 4 (- 1.25) to 8 ( 2.00)] 5 bits, 2^-2
val e = c * d // [-308 (-19.3125) to 616 (38.50)] 11 bits, 2^-4
// Integer without expansion
val aa = new AFix(8, 16, -4 exp) // [8 to 16] 5 bits, 2^-4
val bb = new AFix(1, 15, -4 exp) // [1 to 15] 4 bits, 2^-4
val cc = aa + bb // [9 to 31] 5 bits, 2^-4
AFix
支持无范围扩展的操作。它通过从每个输入中选择对齐的最大和最小范围来实现此目的。
+|
和 -|
分别代表加法和减法操作,这两种操作在执行时不会对数值进行扩展。
不等式运算
AFix
支持标准的不等式运算。
A === B
A =\= B
A < B
A <= B
A > B
A >= B
警告:编译时超出范围的操作将被优化掉!
位移操作
AFix
支持十进制和位移操作
<<
将十进制小数点向左移动,即增加指数值。 >>
将十进制小数点向右移动,即减小指数值。 <<|
将位左移。给小数位追加零。 >>|
将位向右移动。删除小数位。
饱和与舍入
AFix
实现饱和和所有常见的舍入方法。
饱和的工作原理是使 AFix
值的支持值范围饱和。有多个考虑到了指数特性的辅助函数。
val a = new AFix(63, 0, -2 exp) // [0 to 63, 2^-2]
a.sat(63, 0) // [0 to 63, 2^-2]
a.sat(63, 0, -3 exp) // [0 to 31, 2^-2]
a.sat(new AFix(31, 0, -1 exp)) // [0 to 31, 2^-2]
AFix
舍入模式:
// The following require exp < 0
.floor() or .truncate()
.ceil()
.floorToZero()
.ceilToInf()
// The following require exp < -1
.roundHalfUp()
.roundHalfDown()
.roundHalfToZero()
.roundHalfToInf()
.roundHalfToEven()
.roundHalfToOdd()
这些舍入模式的数学示例在这里得到了更好的解释:Rounding - Wikipedia
所有这些模式都会产生指数为 0 的 AFix
值。如果需要舍入到不同的指数,请考虑移位或使用带有 truncated
标签的赋值。
赋值
AFix
会在赋值时自动检查并扩大范围和精度。默认情况下,将一个 AFix
值赋值给另一个范围或精度更小的 AFix
值是错误的。
.truncated
函数用于控制如何赋值给较小的类型。
def truncated(saturation: Boolean = false,
overflow : Boolean = true,
rounding : RoundType = RoundType.FLOOR)
def saturated(): AFix = this.truncated(saturation = true, overflow = false)
RoundType
:
RoundType.FLOOR
RoundType.CEIL
RoundType.FLOORTOZERO
RoundType.CEILTOINF
RoundType.ROUNDUP
RoundType.ROUNDDOWN
RoundType.ROUNDTOZERO
RoundType.ROUNDTOINF
RoundType.ROUNDTOEVEN
RoundType.ROUNDTOODD
当设置 saturation
标志时,系统会在数值超出指定数据类型的界限时,自动将其调整至该类型的有效范围,以防止溢出。
overflow
标志将允许在舍入后直接赋值,而不进行范围检查。
将精度较高的值分配给精度较低的值时,始终需要进行舍入。