package DDG::Goodie::PrimeFactors;
# ABSTRACT: Returns all the prime factors of the entered number
use strict;
use DDG::Goodie;
use Math::Prime::Util 'factor_exp', 'is_prime';
use bignum;
use utf8;
zci answer_type => "prime_factors";
zci is_cached => 1;
triggers startend => (
'prime factors',
'prime factors of',
'the prime factors of',
'factorization of',
'prime factorization',
'prime factorization of',
'factorize',
'prime factorize',
);
primary_example_queries 'prime factors of 30';
secondary_example_queries '72 prime factors', 'factorize 128';
description 'Returns the prime factors of the entered number';
name 'PrimeFactors';
topics 'math';
category 'calculations';
attribution github => [ 'austinheimark', 'Austin Heimark' ];
# This adds exponents to the prime numbers.
# It outputs both text and HTML:
# - 2^2
# - 22
sub format_exp {
my $factor = shift;
if($factor->[1] > 1) {
return "$factor->[0]^$factor->[1]", "$factor->[0]$factor->[1]";
}
return $factor->[0], $factor->[0];
}
# This goes through all the prime factors and formats them in an "n × m" format.
# It outputs both text and HTML.
sub format_prime {
my @factors = @_;
my @text_result = ();
my @html_result = ();
foreach my $factor (@factors) {
my ($text, $html) = format_exp($factor);
push(@text_result, $text);
push(@html_result, $html);
}
return join(" × ", @text_result), join(" × ", @html_result);
}
# This adds commas to the number.
# It converts 10000000 to 10,000,000.
# It was copied from http://perldoc.perl.org/perlfaq5.html#How-can-I-output-my-numbers-with-commas-added%3f
sub commify {
no bignum;
local $_ = shift;
1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
return $_;
}
handle remainder => sub {
# Exit if it's not a digit.
# TODO: We should accept different number formats.
return unless /^\d+$/;
my $start_time = time();
my @factors = ();
# Provide only one second for computing the factors.
eval {
alarm(1);
@factors = factor_exp($_);
};
# Exit if we didn't find anything.
if(@factors == 0) {
return;
}
my $formatted = commify($_);
# If it has only one factor then it is a prime. Except if it's 0 or 1.
my $result;
if(is_prime($_)) {
return "$formatted is a prime number.", html => "$formatted is a prime number.";
} else {
my ($text, $html) = format_prime(@factors);
my $intro = "The prime factorization of $formatted is";
return "$intro $text", html => "$intro $html";
}
};
1;