2016-12-06 299 views
1

我正在閱讀一個excel文件。在其中一列(只包含很長的數字)中,MATLAB將其導入爲CELL(因爲有一個標題)。MATLAB轉換:CELL to DOUBLE;但數字變化

這是進口的樣品:
'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。

UPDATE:
我跑到離回答了這個代碼:
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);

回答

1

更好的答案

答案樓下是公認的答案,但同時拖延的東西,我意識到,這是太聰明瞭。我想你真正想是使用textscan

tableM.v1 = cellfun(@(x) textscan(x, '%u64'), tableM.v1); 

Textscan已經爲指數和小數檢查,去直接Integer類不經過雙,並得到如下ISN溢出權(我的溢出例如」因爲指數矢量也溢出了,所以最好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中,有一個標誌可以告訴它在沒有投射的情況下進行求和。我不知道那個國旗何時發佈,所以你的里程可能會有所不同。如果你沒有這個選項,你將不得不在循環中完成總和。

另一個警告:此功能沒有輸入或輸出檢查,所以(我只是根據它們在ASCII表中的位置轉換數字)和str2uint64('1000000000000000000') = 18446744073709551615(溢出)。使用風險自負。


+0

不錯+1。我很驚訝地發現MATLAB還沒有'str2int *'套件。內部的「雙重」鑄造也是非常奇怪和煩人的。我注意到,出於某種原因,將VPA非標量轉換爲'uint64'時也會發生這種情況:'str ='980000684210053338'; disp(uint64(vpa(str))); disp(uint64(vpa(repmat({str},1,2))));'產生不同的結果,這很荒謬。 – TroyHaskin

+0

這似乎工作,但一個小問題。它將'0,0090'轉換爲'90'或'3,5610'爲'305610'。 – PeyM87

+0

您的示例不包含數字以外的字符。這就是爲什麼我添加了關於錯誤檢查的最後一個警告。該函數還假定您的輸入已經是整數,而不是浮點數,因爲您沒有指出它是一個選項。這將需要一些額外的步驟來搜索小數點指示符,然後截斷數字。 – craigim

1

雙精度數必須在最15 stable decimal places,或如MathWorks puts it ,「double值不能正確地表示大於2的所有整數」「。由於Excel中的數字有18個小數位,因此精確到double的轉換是不可避免的。

爲了避免精度損失,可以將字符串轉換爲使用variable precision arithmetic號:

tableM.v1 = vpa(tableM.v1); % assuming tableM.v1 is a cellstr 

這將很可能會嚴重影響性能,但是這是放的確切表示(至MATLAB原生支持無論如何,128位浮點都可能在很遠的時間和更多的性能密集)。

理論上,uint64也可以精確地保存整數,但似乎並不是一種乾淨的方式來將字符串轉換爲我能找到的一個整數。

+0

我使用此代碼時收到錯誤。我更新了錯誤的問題。 – PeyM87

+0

@ PeyM87這告訴我'tableM.v1'不完全是隻包含數字的字符串數組。這是它工作的唯一方式。 – TroyHaskin