matheburg
matheburg

Reputation: 2180

Matlab function for writing numbers in words

Do you know a Matlab function which allows for converting a given integer number into words (such as provided by this online tool)?

E.g. num2words(2) returning 'two'; num2words(10) returning 'ten'; ...

Upvotes: 2

Views: 2621

Answers (1)

matheburg
matheburg

Reputation: 2180

Here is my implementation, please report any bugs or things you want to improve:

num2words.m

function words = num2words(number)    
    %% integer part
    int_number = floor(number);
    words = int2words(int_number);
    %% digits after the decimal point
    if int_number ~= number
        %% base words
        namesDigits = {'zero', 'one', 'two', 'three', 'four', 'five', ...
                       'six', 'seven', 'eight', 'nine'};
        words = [words, ' point'];
        %% version 1: does not work due to numerical issues
        %while int_number ~= number
        %    number = (number-int_number) * 10;
        %    int_number = floor(number);
        %    words = [words, ' ', namesDigits{int_number+1}]; %#ok<AGROW>
        %end
        %% version 2: based on sprintf
        numStr = sprintf('%.18g', number);
        pointPos = find(numStr == '.');
        numStr = numStr(pointPos+1:end);
        for cIdx = 1:length(numStr)
            int_number = str2num(numStr(cIdx)); %#ok<ST2NM>
            words = [words, ' ', namesDigits{int_number+1}]; %#ok<AGROW>
        end
    end
end

%% 
% This function is implemented according to the modern British short scale
% standard dictionary numbers, cf.
%   http://en.wikipedia.org/wiki/English_numerals
%   http://en.wikipedia.org/wiki/Names_of_large_numbers
function words = int2words(number)
    %% base words
    minus     = 'minus';
    names0    = 'zero';
    names1000 = {'', ' thousand', ' million', ' billion', ' trillion', ...
                 ' quadrillion', ' quintillion', ' sextillion', ...
                 ' septillion', ' octillion', ' nonillion', ...
                 ' decillion', ' undecillion', ' duodecillion', ...
                 ' tredecillion', ' quattuordecillion', ...
                 ' quindecillion', ' sexdecillion', ' septendecillion', ...
                 ' ocotdecillion', ' novemdecillion', ' vigintillion'};

    %% sign    
    if number < 0
        isNegative = true;
        number = -number;
    elseif number == 0
        words = names0;
        return;
    else
        isNegative = false;
    end
    words = '';

    %% checks
    %maxCorrectNumber = 10^18...
    %maxDoableNumber = 10^63...

    %% convert
    cnt = 1;
    while number ~= 0
        num1000 = mod(number,1000);
        number = floor(number / 1000);
        if num1000 > 0
            if ~isempty(words)
                words = [',' words]; %#ok<AGROW>
            end        
            words = [' ' int2words_1to999(num1000), names1000{cnt}, words]; %#ok<AGROW>
        end
        cnt = cnt + 1;
        % check:
        if cnt == length(names1000) + 1
            error('The given number is too large for converting it into words');
        end
    end

    %% add sign
    if isNegative
        words = [minus, words];
    end

    %% trim <- can be removed by more clever whitespace handling inbetween?
    words = strtrim(words);
end

%% numbers between 1 and 999
function words = int2words_1to999(number)
    %% base words
    names1  = {'', 'one', 'two', 'three', 'four', 'five', 'six', ...
               'seven', 'eight', 'nine', 'ten', 'eleven', ...
               'twelve', 'thirteen', 'fourteen', 'fifteen', ...
               'sixteen', 'seventeen', 'eighteen', 'nineteen'};
    names10 = {'', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', ...
               'seventy', 'eighty', 'ninety'};
    %% convert
    num100 = mod(number, 100);
    if num100 < 20
        words = names1{num100+1};
        number = (number - num100) / 100;
    else
        num10 = mod(number, 10);
        words = names1{num10+1};
        if ~isempty(words)
            words = ['-' words];
        end
        number = (number - num10) / 10;
        num10 = mod(number, 10);
        words = [names10{num10} words];
        number = (number - num10) / 10;
    end
    if number > 0
        if ~isempty(words)
            words = [' ', words];
        end
        words = [names1{number+1}, ' hundred', words];
    end
end

Examples

num2words(18) = 'eighteen'

num2words(23) = 'twenty-three'

num2words(-100) = 'minus one hundred'

num2words(20) = 'twenty'

num2words(398) = 'three hundred ninety-eight'

num2words(54689398) = 'fifty-four million, six hundred eighty-nine thousand, three hundred ninety-eight'

num2words(0.1233291010) = 'zero point one two three three two nine one zero one'

num2words(5468939298457898) = 'five quadrillion, four hundred sixty-eight trillion, nine hundred thirty-nine billion, two hundred ninety-eight million, four hundred fifty-seven thousand, eight hundred ninety-eight'

Upvotes: 4

Related Questions