IDL 中正浮点数的六十进制编码
18492 给本文评分:
3.5
IDL 中正浮点数的六十进制编码
匿名 2017年2月2日,星期四
这里是一个使用有限符号集高效表示数字的示例。我使用一组 60 个符号(或字符)将浮点数编码为任意选定长度的字符串。字符串越长,数字的精度可能就越高。
以下是一个表示示例,为了保持示例简短,这里仅限于正数。
IDL> a=[14.33, 3.1415, 12345]
IDL> a
14.330000 3.1415000 12345.000
IDL> base60(a)
FotV*
FdiDx
HdzS*
IDL> base60(a, precision=8)
FotV**aO
FdiDx*^c
HdzS****
IDL> base60(base60(a)) - a
-4.5533356836102712e-006 -4.6258149324351905e-006 -0.016666666666424135
IDL> base60(base60(a, precision=8)) - a
-9.2104102122902987e-012 -4.6052051061451493e-013 -7.7159711509011686e-008
在这个例子中,可以看到 5 位数的表示不如 8 位数的表示接近原始数字。
base60 函数的代码示例如下。
;
; 将数值类型转换为六十进制表示
; 将六十进制字符串转换为浮点表示
; PRECISION 仅用于确定编码时使用多少个符号,
; 在解码时被忽略。
function Base60, input, precision=precision
compile_opt idl2,logical_predicate
; 仅为编码设置默认精度为 5 位数字
if ~keyword_set(precision) then precision = 5
; 六十进制的符号集
symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*'
base = strlen(symbols)
; 从符号到值的快速转换
lut = bytarr(256)
lut[byte(symbols)] = bindgen(base)
if isa(input, /string) then begin
; 将 base60 字符串转换为浮点数
; 先找到指数
scale = replicate(double(base),n_elements(input)) ^ $
(lut[byte(strmid(input,0,1))] - base/2)
res = dblarr(n_elements(input))
for i=max(strlen(input))-1,1,-1 do begin
dig = lut[byte(strmid(input,i,1))]
res += dig
res /= base
endfor
res *= scale
endif else begin
; 将浮点数转换为 base60 字符串
; 首先编码指数(比例)
ex = intarr(n_elements(input))
arr = input
dbase = double(base)
repeat begin
dec = fix(arr ge 1)
ex += dec
arr *= dbase ^ (-dec)
inc = fix(arr lt 1/dbase)
ex -= inc
arr *= dbase ^ inc
endrep until array_equal(arr lt 1 and arr ge 1/dbase,1b)
if max(ex) ge base/2 || min(ex) lt -base/2 then begin
message, '数字超出了可表示的范围'
endif
bsym = byte(symbols)
res = string(bsym[reform(ex+base/2,1,n_elements(ex))])
for i=1,precision-1 do begin
arr *= base
fl = floor(arr)
arr -= fl
res += string(bsym[reform(fl,1,n_elements(fl))])
endfor
endelse
return, res
end