MATLAB 转换:CELL 到 DOUBLE;但数字变了
MATLAB conversion: CELL to DOUBLE; But numbers change
我正在读取 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
我收到了这个错误:
Warning: Support of strings that are not valid variable names or
define a number will be removed in a future release. To create
symbolic expressions, first create symbolic variables and then
use operations on them.
In sym>convertExpression (line 1536)
In sym>convertChar (line 1441)
In sym>tomupad (line 1198)
In sym (line 177)
In cell2sym (line 28)
In sym>tomupad (line 1208)
In sym (line 177)
In vpa (line 44)
Error using symengine
New array must have the same number of elements as the original
array.
Error in sym/reshape (line 50)
ySym = mupadmex('symobj::reshape',x.s,args{:});
Error in cell2sym (line 34)
S = reshape(sym([Csym{:}]), size(C));
Error in sym>tomupad (line 1208)
xsym = cell2sym(x);
Error in sym (line 177)
S.s = tomupad(x);
Error in vpa (line 44)
ss = sym(s);
双精度数最多有 15 stable decimal places or, as MathWorks puts it,“double
值无法正确表示大于 253 的所有整数”。由于 Excel 数字的长度为 18 位有效小数位,因此 double
转换的精度损失是不可避免的。
为避免精度损失,您可以将字符串转换为使用 variable precision arithmetic:
的数字
tableM.v1 = vpa(tableM.v1); % assuming tableM.v1 is a cellstr
这很可能会降低性能,但这是精确表示的回报(直到 MATLAB 本身支持 128 位浮点,这可能在时间上很遥远,而且性能更密集)。
理论上,uint64
也可以准确地保存整数,但似乎没有一种干净的方法可以将字符串转换为 n 位我能找到的整数。
更好的答案
下面的答案是公认的答案,但是在拖延某事时,我意识到它太聪明了。我想你真正想要的是使用textscan
:
tableM.v1 = cellfun(@(x) textscan(x, '%u64'), tableM.v1);
Textscan 已经检查了指数和小数,直接进入整数 class 而不通过 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 中的位置转换数字 table)和 str2uint64('1000000000000000000') = 18446744073709551615
(溢出)。使用风险自负。
我正在读取 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
我收到了这个错误:
Warning: Support of strings that are not valid variable names or define a number will be removed in a future release. To create symbolic expressions, first create symbolic variables and then use operations on them.
In sym>convertExpression (line 1536)
In sym>convertChar (line 1441)
In sym>tomupad (line 1198)
In sym (line 177)
In cell2sym (line 28)
In sym>tomupad (line 1208)
In sym (line 177)
In vpa (line 44)
Error using symengine
New array must have the same number of elements as the original array.Error in sym/reshape (line 50)
ySym = mupadmex('symobj::reshape',x.s,args{:});Error in cell2sym (line 34)
S = reshape(sym([Csym{:}]), size(C));Error in sym>tomupad (line 1208)
xsym = cell2sym(x);Error in sym (line 177)
S.s = tomupad(x);Error in vpa (line 44)
ss = sym(s);
双精度数最多有 15 stable decimal places or, as MathWorks puts it,“double
值无法正确表示大于 253 的所有整数”。由于 Excel 数字的长度为 18 位有效小数位,因此 double
转换的精度损失是不可避免的。
为避免精度损失,您可以将字符串转换为使用 variable precision arithmetic:
的数字 tableM.v1 = vpa(tableM.v1); % assuming tableM.v1 is a cellstr
这很可能会降低性能,但这是精确表示的回报(直到 MATLAB 本身支持 128 位浮点,这可能在时间上很遥远,而且性能更密集)。
理论上,uint64
也可以准确地保存整数,但似乎没有一种干净的方法可以将字符串转换为 n 位我能找到的整数。
更好的答案
下面的答案是公认的答案,但是在拖延某事时,我意识到它太聪明了。我想你真正想要的是使用textscan
:
tableM.v1 = cellfun(@(x) textscan(x, '%u64'), tableM.v1);
Textscan 已经检查了指数和小数,直接进入整数 class 而不通过 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 中的位置转换数字 table)和 str2uint64('1000000000000000000') = 18446744073709551615
(溢出)。使用风险自负。