Matlab代码中的基础转换错误

5
我创建了以下简单的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) 

一个在基数为201时由七(7)个数字组成的矢量能够正常工作,但是同样有着相对较小的数字且理论上应该成功转换的在基数为200时的矢量并不能返回期望的结果。


你可以尝试转到单元格,这似乎更容易。另一种选择是设置最大允许数量,然后用零填充。通常情况下都是这样做的原因。 - patrik
@DennisJaheruddin,这种代码调试有点困难,因为它涉及到非常大的数字,正如我所说,它除了一些“奇怪”的情况(就像我提到的那个)之外都运行良好,所以我主要希望其他人也遇到过这种情况,因为我的转换函数直接从我们对数字进位制的理论中得出(除非我犯了一些明显的错误)。 - ealiaj
@patrik 我不确定我正确理解了你的建议,数字[200]应该在范围内,因为比它大的那个[201]似乎是可以的。 - ealiaj
2
使用基数200和向量[199,199,199,199,199,199,199],在循环的最后一步中,base2decimal函数计算出63999999999999.0*200+199,由于浮点数限制,我认为结果应该是12800000000000000.0而不是12799999999999999.0。但这不应该是浮点误差,因为eps(12799999999999999.0) = 0.5,所以它似乎可以保持这种精度...尽管如eps(1.28e16)=2,计算出的数字是最后一个整数值双精度浮点数,其精度小于1。 - RTL
@patrik 不是我问的问题,尽管你是正确的,但在表示非常大的基数中,显然应该使用向量来表示数字。 - ealiaj
显示剩余6条评论
2个回答

1

一个初步的评论:调用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

这意味着这两个值共享“true”表示为2017−1,巧合的是这是您预期的值。
TL;DR
当存储在double中时,2007−1被不准确地表示为2007,而2017−1则被准确表示。
“较大的数字比较小的数字更不准确地表示”是一个误解:如果这是真的,那么就没有可以“精确”表示的大数。

0

从您自己的观察来看:

  1. 代码在大多数情况下都可以正常工作
  2. 对于大数字,代码可能会出现小错误

嫌疑人显然:

舍入问题似乎在这里给您带来了麻烦。这也可以从@RTL在评论中的说明中得到证明。


第一个问题现在应该是: 1. 对于这么大的数字,您是否需要完美的准确性?或者有时候稍微偏差一点点也可以接受吗?
如果回答是肯定的,我建议您尝试使用不同的存储格式。 简单的解决方案是使用大整数:
uint64

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


我不喜欢这个。你需要让每个“数字”都有相同的位数,例如一个在105进制下的数字211应该是一个向量v=[002,001]。这也适用于小数。 - patrik
@patrik 不确定评论的内容,但我也找到了一对函数:bigbase2decdec2bigbase。这些可能是无错误的,但当然它们仍然会有限制。请参见此页面底部。 - Dennis Jaheruddin
这确实很好,但我的意思是,与十进制数中每个十进制数字作为数字的一个元素相同,大于十进制的基仍需要由一个元素组成。由于Matlab仍使用十进制,因此您需要想出其他办法。例如,使用元素向量表示。例如,在100进制下215为[02,15] - patrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接