zeroclickinfo-goodies/lib/DDG/Goodie/PrimeFactors.pm

107 lines
2.5 KiB
Perl
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
# - 2<sup>2</sup>
sub format_exp {
my $factor = shift;
if($factor->[1] > 1) {
return "$factor->[0]^$factor->[1]", "$factor->[0]<sup>$factor->[1]</sup>";
}
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;