我正在阅读excel文件。在其中一列(仅包含很长的数字)中,MATLAB将其作为CELL导入(因为它有一个标题)。
这是导入的样本:
' 980000684210053338'
这些是我的尝试:
转换为DOUBLE但数字更改
tableM.v1 = cellfun(@str2num,tableM.v1);
转换为DOUBLE但数字更改
tableM.v1 = cellfun(@str2double,tableM.v1);
转换为CHAR但数字正确
tableM.v1 = cell2mat(tableM.v1);
如何在保持正确值的同时将此CELL转换为DOUBLE?
由于
P.S。我正在使用MATLAB R2016a。
更新
我从答案中运行了这段代码:
tableM.v1 = vpa(tableM.v1); % assuming tableM.v1 is a cellstr
我收到了这个错误:
警告:支持无效变量名称的字符串或 定义一个号码将在以后的版本中删除。创造 符号表达式,首先创建符号变量然后 对它们使用操作。
在sym> convertExpression(第1536行)中 在sym> convertChar(第1441行)中 在sym> tomupad(第1198行)中 在sym(第177行)
在cell2sym(第28行)中 在sym> tomupad(第1208行)中 在sym(第177行)
在vpa(第44行)
使用symengine时出错 新数组必须与原始数组具有相同数量的元素 阵列。sym / reshape中的错误(第50行)
ySym = mupadmex(' symobj :: reshape',x.s,args {:});cell2sym中的错误(第34行)
S =重塑(sym([Csym {:}]),大小(C));sym> tomupad中的错误(第1208行)
xsym = cell2sym(x);sym中的错误(第177行)
S.s = tomupad(x);vpa中的错误(第44行)
ss = sym(s);
答案 0 :(得分:1)
双精度数最多15 stable decimal places或MathWorks puts it,“double
值不能正确表示大于2 53 的所有整数”。由于Excel数字长度为18位有效小数位,因此double
转换的精度损失是不可避免的。
为避免精度损失,您可以将字符串转换为使用variable precision arithmetic的数字:
tableM.v1 = vpa(tableM.v1); % assuming tableM.v1 is a cellstr
这很可能会扼杀性能,但这是精确表示的回报(直到MATLAB本身支持128位浮点,这可能是时间太长而且性能密集程度更高)。
理论上,uint64
也可以准确地保存整数,但似乎没有一种干净的方法将字符串转换为我能找到的 n 位整数
答案 1 :(得分:1)
更好的答案
下面的回答是接受的答案,但在拖延某事时,我意识到它太聪明了。我认为您真正想要的是使用textscan
:
tableM.v1 = cellfun(@(x) textscan(x, '%u64'), tableM.v1);
Textscan已经检查了指数和小数,直接转到整数类而不通过double,并且正确溢出(下面的溢出示例不太正确,因为指数向量也溢出。最大uint64
是实际上是9223372036854775807)。然而,不是一个漂亮的向量,你最终将得到一个数字的单元格数组,因为这是textscan
吐出的内容。任何格式错误的数字都会导致空单元格,在转换为向量之前,您必须处理这些单元格。
>> in = {'cat', '1e10', '980000684210053338};
>> out = cellfun(@(x) textscan(x, '%u64'), in)
out =
1×3 cell array
[0×1 uint64] [10000000000] [980000684210053338]
修复后,您可以使用cell2mat
转换为矢量。
原始答案
正如其他答案所指出的那样,由于精度损失,双打不能保持这些数字。您需要将它们转换为64位整数,而无需先通过double
过滤器。试试这个三行函数:
function out = str2uint64(in)
% Convert the digits into an array of numbers and cast to
% uint64
in = uint64(in - 48);
% Create the order of magnitude for each digit and convert
% that also to uint64
exponents = uint64(logspace(numel(in)-1, 0, numel(in)));
% Why would sum default to convert your numbers to doubles?!?
% The 'native' tag is recent, I believe, but if you have it,
% it will preserve the data type.
out = sum(in .* exponents, 'native');
end
使用:
tableM.v1 = cellfun(@str2uint64,tableM.v1);
有一点需要注意的是,由于某些愚蠢的原因,当MATLAB对数字求和时,它会将它们转换为double
。在当前版本的R2016b中,有一个标志告诉它在没有强制转换的情况下求和。我不知道那个国旗何时被释放,所以你的里程可能会有所不同。如果您没有该选项,则必须在循环中进行总和。
另一个警告:此函数没有输入或输出检查,因此str2uint64('cat') = 5658
(我只是根据它们在ASCII表中的位置转换数字)和str2uint64('1000000000000000000') = 18446744073709551615
(溢出)。使用风险自负。