基转换误差的matlab代码



我创建了以下简单的matlab函数来将一个数字从任意进制转换为十进制并返回

这是第一个

function decNum = base2decimal(vec, base)
decNum = vec(1);
for d = 1:1:length(vec)-1
    decNum = decNum*base + vec(d+1);     
end 

这是另一个

function baseNum = decimal2base(num, base, Vlen)
ii = 1;
if num == 0
    baseNum = 0;
end
while num ~= 0 
    baseNum(ii) = mod(num, base);
    num = floor(num./base);
    ii = ii+1;
end
baseNum = fliplr(baseNum);
if Vlen>(length(baseNum))
    baseNum = [zeros(1,(Vlen)-(length(baseNum))) baseNum ];
end

由于有限制的数字可以是多大,这些函数不能成功地转换不同的大向量,但在测试它们时,我注意到以下错误

让我们使用以下测试函数

num = 201;
pCount = 7
x=base2decimal(repmat(num-1, 1, pCount), num)
repmat(num-1, 1, pCount)
y=decimal2base(x, num, 1)
isequal(repmat(num-1, 1, pCount),y) 
base201中具有七(7)个数字的假设向量可以正常工作,但是具有base200的相同向量不会返回预期的结果,即使它更小,理论上应该转换成功。

(一个初步的注释:调用base2decimal不会得到一个十进制数,而是一个数字:-D)

这是由于浮点精度有限(在本例中是double)。要测试它,只需在MATLAB命令窗口输入:

>> 200^7 - 1 == 200^7
ans = 
     1
>> mod(200^7 - 1, 200)
ans =
     0

意味着以200为基数的数字的值(精确地说是2007&减1)被精确地表示为2007,而表示的"真实"值是2007

另一方面:
>> 201^7 - 1 == 201^7
ans =
 1

所以这两个数字仍然表示相同,但是

>> mod(201^7 - 1, 201)
ans =
   200

,这意味着这两个值共享2017& - 1的"真实"表示,这是您所期望的值。

TL;博士

double中存储时,2007& - 1被不准确地表示为2007,而2017& - 1被准确地表示。

"较大的数字比较小的数字更不准确地表示"是一个误解:如果这是真的,那么就不存在可以精确地表示的大数。

从你自己的观察来看:

  1. 代码在大多数情况下工作正常
  2. 代码可以给出大数字的小错误

嫌疑人明显:

四舍五入的问题似乎会让你感到困惑。评论中的@RTL也说明了这一点。


第一个问题现在应该是:1. 这么大的数字需要精确吗?或者,如果它有时偏离相对较小的量是可以的吗?

如果答案是肯定的,我建议您尝试不同的存储格式。简单的解决方案是使用大整数:

uint64

另一种选择是创建自己的存储格式。如果需要更大的数字,这是必需的。我认为你可以用单元格数组和一些技巧来覆盖很大的范围,但当然,之后很难在不失去你努力工作的准确性的情况下组合这些数字。

最新更新