2015-04-02 4 views
0

Это моя первая программа Erlang. Мне нужна помощь с моим кодом. Я только что узнал, что я не могу вызывать функции в охранниках, поэтому я попытался внедрить «случай» в функцию-факторе/3. Код компилируется, но я получаю следующее сообщение об ошибке:Основная программа факторизации

*** Ошибка исключения: произошла ошибка при оценке арифметического выражения в программе функции: фактор/3 (program.erl, линия 24) *

-module(program). 
    -export([first/1, isProduct/1, factor/1]). 


    %returns the first prime factor of the parameter(an integer greater than 1) passed to the function 
    first(Num) -> first(Num, 2). 

    %private helper function for first(Num) 
    first(Num, Count) when (Num rem Count) == 0 -> Count; 
    first(Num, Count) -> Count = Count + 1, 
    first(Num, Count). 


    %returns the prime factorization of Num as a list of prime numbers 
    factor(Num) -> factor(Num, Num, 1, [Rest, first(Num)]) 

    %helper function for factor(Num) 
    factor(Num, StaticNum, Count, [First|Rest]) when Count == StaticNum -> [First, Rest]; 
    factor(Num, StaticNum, Count, [First|Rest]) -> 
    factor(Num div lists:last([Rest]), StaticNum, (Count * [Rest]), [Rest|first(Num div lists:last([Rest])])). 
+0

На последней строке вы пытаетесь разделить число на список: 'Num/[Rest]', что почти наверняка является источником вашей ошибки, поскольку это невозможно. Что вы на самом деле пытаетесь сделать там? Вам нужно переосмыслить свой подход и изменить свой код. Также обратите внимание, что вы скорее всего хотите использовать 'div', а не'/', потому что вы пытаетесь сделать целочисленное деление. –

+0

В конце списка есть элемент, который я хочу разделить. Как я могу это сделать. –

+0

'Rest' - это хвост списка, поэтому он может быть пустым. –

ответ

3

Я изменил ваш код, потому что написанная вами версия не может скомпилироваться.

Здесь много проблем.

first(Num, Count) -> 
    Count = Count + 1, 
    first(Num, Count). 

Переменные не изменяемые! Вы не можете сделать это, но вы можете вспомнить первый/2 с новыми параметрами:

first(Num, Count) -> 
    first(Num, Count+1). 

Кроме того, эта функция никогда не остановится, если он вызывается с параметром 1. Вам необходимо добавить результат для этого.

%returns the product of factors-in-a-list. 
isProduct([]) -> 0; 
isProduct([First|Rest]) -> First * isProduct(Rest). 

Эта функция всегда возвращает 0, так как она всегда заканчивается обнаружением пустого списка. Вы должны написать isProduct([]) -> 1;

Когда вы находите последний фактор вы вставить его в списке с плохим синтаксисом: использовать [First|Rest]; не [First, Rest];

, когда вы хотите перебрать, первый параметром является текущим остальным Числа, поэтому для следующим шагом должно быть Num/Next с Next = first (Num). Обратите внимание, что в синтаксисе [First|Rest] Сначала это элемент (здесь целое число), а Rest - это список, и вы не можете использовать список для арифметической операции.

Последнее, что вы хотите добавить новый элемент в список простых чисел, это будет Next = first(Num), и вы должны положить его в начало списка и продолжить с Num div Next (это относится к первому вызову factor/3)

ваш код становится:

-module(program). 
    -export([factor/1]). 


    %returns the first prime factor of the parameter(an integer greater than 1) passed to the function 
    first(1) -> 1; 
    first(Num) -> first(Num, 2). 

    %private helper function for first(Num) 
    first(Num, Count) when (Num rem Count) == 0 -> Count; 
    first(Num, Count) -> first(Num, Count+1). 

    %returns the product of factors-in-a-list. 
    isProduct([]) -> 1; 
    isProduct([First|Rest]) -> First * isProduct(Rest). 



    %returns the prime factorization of Num as a list of prime numbers 
    factor(Num) when is_integer(Num), Num > 0 -> 
    First = first(Num), 
    factor(Num div First, Num,[First]). 

    %helper function for factor(Num) 
    factor(Num, StaticNum, [First|Rest]) -> 
    case isProduct([First|Rest]) == StaticNum of 
     true -> [First|Rest]; 
     false -> 
      Next = first(Num), 
      factor(Num div Next, StaticNum, [Next,First|Rest]) 
    end. 

вашей версия не оптимизирована, так как перезапуск первого в 2 каждый раз (важно, когда есть много простых множителей) и условие остановки не оптимизировано (важно, когда есть некоторые «большие» основные факторы). Я бы написать так:

decomp(N) when is_integer(N), (N > 0) -> 
    lists:reverse(decomp(N,[],2)). 

decomp(N,R,I) when I*I > N -> [N|R]; 
decomp(N,R,I) when (N rem I) =:= 0 -> decomp(N div I,[I|R],I); 
decomp(N,R,2) -> decomp(N,R,3); 
decomp(N,R,I) -> decomp(N,R,I+2). 

Вот результат для 2-й версий, измеренных с таймером: дц/3 (на Windows 7), разность времени выполнения огромна, более чем 15000 раз быстрее, для этого Пример:

2> timer:tc(program,factor,[1234567893200]). 
{91349000,[3086419733,5,5,2,2,2,2]} 
3> timer:tc(program,decomp,[1234567893200]). 
{6000,[2,2,2,2,5,5,3086419733]} 
+0

Спасибо. У меня есть много обзоров/учебы, которые нужно сделать сейчас, когда вы оба исправили мой код и предложили превосходное решение. Более быстрое решение 15000x будет очень полезно для анализа, но я очень доволен вашими изменениями в исходном коде и использованием isProduct() из OP (pre edit). Я все еще разочарован тем, что мне не удалось полностью решить эту проблему из-за схемы и ракетки и документа erlang. –

+0

Мне очень нравится использовать erlang. Если вы начнете, не отчаивайтесь, потребуется некоторое время для использования не изменяемой переменной и рекурсии повсюду. Но есть много доступной документации и один чрезвычайно ценный веб-сайт для начала обучения: [LYSE] (http://learnyousomeerlang.com/content). – Pascal

1

Я переписал вам код, надеюсь, что я правильно понимаю вашу задачу.

-module(program). 
-export([first/1]). 

first(Num) when Num >1,is_integer(Num) ->{ok,factor(Num,2)}; 
first(Num)-> {err,Num}. 

factor(Num,Count) when Count>Num+1->[]; 
factor(Num,Count)->case Num rem Count of 
        0->[Count|factor(Num div Count,Count)]; 
        _->factor(Num,Count+1) 
        end. 
Смежные вопросы