【发布时间】:2010-04-08 18:13:17
【问题描述】:
我想实现一个版本的本福德定律 (http://en.wikipedia.org/wiki/Benford%27s_law) 这基本上要求一个数字的第一位数字来对分布进行分析。
1934---> 1
0.04 ---> 4
-56 ---> 5
你如何在 MATLAB 中做到这一点?
【问题讨论】:
标签: matlab benfords-law
我想实现一个版本的本福德定律 (http://en.wikipedia.org/wiki/Benford%27s_law) 这基本上要求一个数字的第一位数字来对分布进行分析。
1934---> 1
0.04 ---> 4
-56 ---> 5
你如何在 MATLAB 中做到这一点?
【问题讨论】:
标签: matlab benfords-law
function res = first_digit(number)
number = abs(number);
res = floor(number / (10 ^ floor(log10(number))));
end
它适用于所有实数(有关极端情况,请参阅 gnovice 的评论)
【讨论】:
number = eps(realmin)。诚然,这不是您会遇到的可能场景。我只是看到解决方案在极值上的表现如何。
有几种方法可以做到这一点...
使用REGEXP:
wholeNumber = 1934; %# Your number
numberString = num2str(wholeNumber,16); %# Convert to a string
matches = regexp(numberString,'[1-9]','match'); %# Find matches
firstNumber = str2double(matches{1}); %# Convert the first match to a double
使用ISMEMBER:
wholeNumber = 0.04; %# Your number
numberString = num2str(wholeNumber,16); %# Convert to a string
isInSet = ismember(numberString,'123456789'); %# Find numbers that are
%# between 1 and 9
numberIndex = find(isInSet,1); %# Get the first number index
firstNumber = str2double(numberString(numberIndex)); %# Convert to a double
编辑:
在the MathWorks blogs 之一上出现了有关此主题的一些讨论。那里提供了一些有趣的附加解决方案。提出的一个问题是矢量化解决方案,所以这是我想出的一个矢量化版本:
numberVector = [1934 0.04 -56];
numberStrings = cellstr(num2str(numberVector(:),16));
firstIndices = regexp(numberStrings,'[1-9]','once');
firstNumbers = cellfun(@(s,i) s(i),numberStrings,firstIndices);
【讨论】:
使用 log10 和 floor 内置函数,
floor(x./10.^floor(log10(x)))
也返回数组中所有元素的第一位。
【讨论】:
让我添加另一个基于字符串的解决方案(也是矢量化的):
FirstDigit = @(n) sscanf(num2str(abs(n(:)),'%e'), '%1d', numel(n));
并在此处提到的案例中进行了测试:
>> FirstDigit( [1934 0.04 -56 eps(realmin)] )
ans =
1
4
5
4
【讨论】: