Engee 中的定点算术(固定点
在数值计算领域,绝大多数问题都使用浮点数("Float32"、"Float64")来解决。然而,在实际系统中,如微控制器、DSP、FPGA 或 ASIC,使用浮点类型可能不可取或不可能。例如,在 STM32 系列微控制器中,基本型号没有 "浮点 "硬件支持,浮点运算比整数运算慢得多。在这种情况下,会使用定点运算("Fixed-Point"),小数点数值以整数格式编码,小数部分的长度预先确定。
定点("Fixed-Point")是一种使用普通整数和预定比例(小数部分的位数)表示小数值的方法。它不使用资源密集型浮点运算("Float32"、"Float64"),而是使用一种简单的整数格式,其中 "二进制逗号 "按给定位数移位。
例如,如果小数部分的长度为 ,那么数字 将被存储为整数值 ,因为将内部值(stored_integer
)转换为实数值(real_value
)的公式 将导致 。从公式中可以看出,内部值被存储并等于 ,但在计算过程中会被解释为 。
这种运算具有以下优点:
在文章中阅读有关定点运算的更多信息guide/hdl-fixed-point-arithmetic.adoc#fixed-point-arithmetic
Engee 中的定点算术
为了处理定点运算,Engee 使用了自己的软件包 EngeeFixedPoint.jl
,它取代了标准的 Julia 软件包 FixedPointNumbers.jl
。与经典软件包不同的是,EngeeFixedPoint.jl
提供了高级功能以及对定点数的表示和行为的精确控制—这在资源受限的系统、将计算转移到HDL 以及严格精度的问题中尤为重要。
EngeeFixedPoint.jl "包是一个标准*Engee*包,包含在默认用户环境中,因此无需在代码中明确调用(通过 "import"/"using")。 |
在 Engee 中,定点数的类型如下:
Fixed{S, W, f, T} <: FixedPoint
在哪里?
由于在数据处理的所有阶段都采用了安全键入和明确的行为方式,因此这种格式可让您准确指定数字的存储、解释和参与计算的方式。
为方便起见,``EngeeFixedPoint.jl''提供了多种指定定点类型的方法,从完全手动指定到自动输出。
S, W, f, T = 1, 25, 10, Int32
dt1 = Fixed{S, W, f, T}
dt2 = fixdt(S, W, f)
dt3 = fixdt(Fixed{S, W, f})
dt4 = fixdt(dt2)
println(dt1 == dt2 == dt3 == dt4) # 真的
在哪里?
-
dt1 = Fixed{S, W, f, T}
- 完整手册描述; -
dt2 = fixdt(S, W, f)
- 简化创建,自动选择类型 ; -
dt3 = fixdt(Fixed{S, W, f})
- 根据现有描述获取类型; -
dt4 = fixdt(dt2)
- 重复使用,从现有类型创建副本。
所有这些选项都会创建相同的类型 Fixed{1, 25, 10, Int32}
,可根据任务使用:
-
当需要控制所有参数时,完整描述(
dt1
)非常有用; -
简化方式 (
dt2
)适用于典型情况,并能缩短代码; -
从类型中获取类型 (
dt3
),在生成代码或键入数据时非常有用; -
重复使用 (
dt4
)有助于处理参数化结构,而无需重新输入参数。
固定 "类型构造函数
接下来,让我们看看在 Engee 中处理定点的具体场景。
例如,可以直接设置类型并传递值:
x = Fixed{1, 15, 2}(25)
结论
fi(6.25, 1, 15, 2)
这意味着 是整数表示(stored_integer
),根据公式 ,实数值(real_value
)将等于 。
固定{S, W, f}(i::T)
。
通过整数表示创建定点的构造函数 Fixed{S, W, f}(i::T)
有以下条件:
-
格式参数:
S
(带符号)、W
(位宽)、f
(小数部分); -
类型为
T
的整数值i
(内部表示)。
S,W,f=1,15,2 #有符号,15位,2小数位
i = 25
X=Fixed{S,W,f}(i) #从整数创建
结论
菲(6.25, 1, 15, 2) # 等效表示
固定{S, W, f, T1}(i::T2)`。
与前一个构造函数类似,但可以明确指定存储类型。类型将根据参数 S
、W
、f
自动匹配,与指定的 T1
无关。
T = Int128
x = Fixed{S, W, f, T}(i) # 指示存储类型
结论
菲(6.25, 1, 15, 2) # 结果是相同的
来自 FixedPointNumbers.jl 的构造函数
尽管使用了新的 EngeeFixedPoint.jl
包,但它仍保留了与 FixedPointNumbers.jl
包的兼容性,以支持许多构造函数。仅支持有符号类型。
支持
-
Fixed{T, f}(i::Integer, _)
- 以整数表示的构造函数。接受类型T
和参数f
; -
Fixed{T, f}(value)
- 以实数(float
)为单位的构造函数。
示例
T = Int32
x1 = Fixed{T, f}(i, nothing) # 从整数
x2 = Fixed{T, f}(i) # 从一个实数
结论
6.25 #第一个构造函数的结果
25.0 #第二个构造函数的结果
使用数组和矩阵
程序库全面支持定点数的矢量和矩阵运算。所有操作都会保留元素类型,并自动将指定精度参数应用于所有数组元素。
向量
创建并处理一维数组。定点参数适用于所有元素:
s, w, f = 1, 62, 7 # 有符号类型,62位,7位小数部分
v = [1, 2, 3] # 资料来源
# 不同的创作方式:
x1 = fi(v, s, w, f) # 指定显式参数
x2 = fi(v, fixdt(s, w, f)) # 通过数据类型
x3 = fi(v, s, w) # 具有自动小数部分检测功能
println(x1)
println(x1 == x2)
println(x3)
输出:
Fixed{1, 62, 7}[1.0, 2.0, 3.0]
true
Fixed{1, 62, 59}[1.0, 2.0, 3.0]
复杂矩阵
完全支持多维数组中的复数:
s, w, f = 1, 62, 7
m = [im 2.5; -1.2im 25-im]
# 创造的工作方法:
x1 = fi(m, s, w, f) # 指定显式参数
x2 = fi(m, fixdt(s, w, f)) # 通过数据类型
println(x1)
println(x1 == x2)
输出
Complex{Fixed{1, 62, 7, Int64}}[fi(0.0, 1, 62, 7) + fi(1.0, 1, 62, 7)*im fi(2.5, 1, 62, 7) + fi(0.0, 1, 62, 7)*im; fi(0.0, 1, 62, 7) - fi(1.203125, 1, 62, 7)*im fi(25.0, 1, 62, 7) - fi(1.0, 1, 62, 7)*im]
true
数学运算
系统会自动为运算结果选择最佳格式,保持准确性并防止溢出。支持所有基本算术运算(加、减、乘、除):
x1 = fi(1.5, 0, 15, 3)
x2 = fi(1.5, 1, 25, 14)
y1 = x1+x2
y2 = x1-x2
y3 = x1*x2
y4 = x1/x2
println(y1)
println(y2)
println(y3)
println(y4)
println(typeof(y1))
println(typeof(y2))
println(typeof(y3))
println(typeof(y4))
println(x1 == x2)
println(x1 <= x2)
println(x1 > x2)
结论
3.0
0.0
2.25
0.0
Fixed{1, 28, 14, Int32}
Fixed{1, 28, 14, Int32}
Fixed{1, 40, 17, Int64}
Fixed{1, 25, -11, Int32}
true
true
false
四舍五入
通过各种四舍五入策略,您可以控制计算的精确度。默认情况下,使用 RoundNearestTiesUp 四舍五入。
x = fi(1.5, 1, 14, 3) # 有符号,14位,3小数位
println(round(x)) # 2.0-舍入到最接近的整数(1.5→2)
println(trunc(x)) # 1.0-删除小数部分
println(ceil(x)) # 2.0-四舍五入到一个更大的整数
println(floor(x)) # 1.0-向下舍入到较小的整数
其中
-
round
- 银行四舍五入(四舍五入到最接近的偶数0.5
); -
trunc
- 放弃小数部分; -
ceil
- 总是向上; -
floor
- 始终向下。
类型转换(转换)
在与其他库交互时,转换为标准数据类型非常有用。转换时会考虑四舍五入规则。
x = fi(1.5, 1, 12, 4)
y1 = Int64(x)
y2 = UInt8(x)
y3 = Float64(x)
y4 = convert(fixdt(0, 5, 2), x)
println(y1)
println(y2)
println(y3)
println(y4)
println(typeof(y1))
println(typeof(y2))
println(typeof(y3))
println(typeof(y4))
结论
1
1
1.5
1.5
Int64
UInt8
Float64
Fixed{0, 5, 2, UInt8}
结论
总之,"EngeeFixedPoint.jl "软件包具有以下优点:
-
*扩展的类型系统:
-
完全支持有符号和无符号数;
-
任意位大小(任何位大小,而不仅仅是 8/16/32/64/128);
-
灵活的小数部分设置(包括负值和 ,小数部分长度大于字长的情况 )。
-
-
*改进了类型输出规则:
-
*根据平台生成代码:
-
针对目标平台(C 或 Verilog)的不同类型继承规则;
-
128 位边界溢出时的可预测行为(不同于同类产品)。
-
-
*功能扩展: