diff --git a/lib/DDG/Goodie/Conversions.pm b/lib/DDG/Goodie/Conversions.pm index 62bacef7af7..18cb0f69c77 100755 --- a/lib/DDG/Goodie/Conversions.pm +++ b/lib/DDG/Goodie/Conversions.pm @@ -6,6 +6,7 @@ use DDG::Goodie; with 'DDG::GoodieRole::NumberStyler'; use Math::Round qw/nearest/; +use Math::SigFigs qw/:all/; use utf8; use YAML::XS 'LoadFile'; use List::Util qw(any); @@ -41,10 +42,11 @@ my $question_prefix = qr/(?convert|what (?:is|are|does)|how (?:much|many my $factor_re = join('|', ('a', 'an', number_style_regex())); my $guard = qr/^(?$question_prefix)\s?(?$factor_re*)\s?(?$keys)\s(?in|to|into|(?:in to)|from)?\s?(?$factor_re*)\s?(?:of\s)?(?$keys)[\?]?$/i; -# fix precision and rounding: -my $precision = 3; -my $scientific_notation_sig_figs = $precision + 3; -my $nearest = '.' . ('0' x ($precision-1)) . '1'; +# for 'most' results, like 213.800 degrees fahrenheit, decimal places +# for small, but not scientific notation, significant figures +my $accuracy = 3; +my $scientific_notation_sig_figs = $accuracy + 3; +my $nearest = '.' . ('0' x ($accuracy-1)) . '1'; # For a number represented as XeY, returns 1 + Y sub magnitude_order { @@ -139,12 +141,13 @@ handle query_lc => sub { return unless defined $result->{'result'}; - my $formatted_result = sprintf("%.${precision}f", $result->{'result'}); + my $formatted_result = sprintf("%.${accuracy}f", $result->{'result'}); + $formatted_result = FormatSigFigs($result->{'result'}, $accuracy) if abs($result->{'result'}) < 1; # if $result = 1.00000 .. 000n, where n <> 0 then $result != 1 and throws off pluralization, so: $result->{'result'} = nearest($nearest, $result->{'result'}); - if ($result->{'result'} == 0 || magnitude_order($result->{result}) >= 2*$precision + 1) { + if ($result->{'result'} == 0 || magnitude_order($result->{result}) >= 2*$accuracy + 1) { # rounding error $result = convert({ 'factor' => $styler->for_computation($factor), @@ -170,11 +173,11 @@ handle query_lc => sub { } $result->{'result'} = $formatted_result; - $result->{'result'} =~ s/\.0{$precision}$//; + $result->{'result'} =~ s/\.0{$accuracy}$//; $result->{'result'} = $styler->for_display($result->{'result'}); my $computable_factor = $styler->for_computation($factor); - if (magnitude_order($computable_factor) > 2*$precision + 1) { + if (magnitude_order($computable_factor) > 2*$accuracy + 1) { $factor = sprintf('%g', $computable_factor); }; $factor = $styler->for_display($factor); diff --git a/t/Conversions.t b/t/Conversions.t index 4f2c0c78760..68aa40f167d 100755 --- a/t/Conversions.t +++ b/t/Conversions.t @@ -300,13 +300,13 @@ ddg_goodie_test( }) ), 'convert 10ms to seconds' => test_zci( - '10 milliseconds = 0.010 seconds', + '10 milliseconds = 0.0100 seconds', structured_answer => make_answer({ markup_input => '10', raw_input => '10', from_unit => 'milliseconds', - styled_output => '0.010', - raw_answer => '0.010', + styled_output => '0.0100', + raw_answer => '0.0100', to_unit => 'seconds', physical_quantity => 'duration' }) @@ -481,13 +481,13 @@ ddg_goodie_test( }) ), '2 thou to mm' => test_zci( - '2 thousandths of an inch = 0.051 millimeters', + '2 thousandths of an inch = 0.0508 millimeters', structured_answer => make_answer({ markup_input => '2', raw_input => '2', from_unit => 'thousandths of an inch', - styled_output => '0.051', - raw_answer => '0.051', + styled_output => '0.0508', + raw_answer => '0.0508', to_unit => 'millimeters', physical_quantity => 'length' }) @@ -709,13 +709,13 @@ ddg_goodie_test( }) ), '5yrds to km' => test_zci( - '5 yards = 0.005 kilometers', + '5 yards = 0.00457 kilometers', structured_answer => make_answer({ markup_input => '5', raw_input => '5', from_unit => 'yards', - styled_output => '0.005', - raw_answer => '0.005', + styled_output => '0.00457', + raw_answer => '0.00457', to_unit => 'kilometers', physical_quantity => 'length' }) @@ -745,13 +745,13 @@ ddg_goodie_test( }) ), '2500kcal in tons of tnt' => test_zci( - '2,500 large calories = 0.003 tons of TNT', + '2,500 large calories = 0.00250 tons of TNT', structured_answer => make_answer({ markup_input => '2,500', raw_input => '2500', from_unit => 'large calories', - styled_output => '0.003', - raw_answer => '0.003', + styled_output => '0.00250', + raw_answer => '0.00250', to_unit => 'tons of TNT', physical_quantity => 'energy' }) @@ -1141,13 +1141,13 @@ ddg_goodie_test( }) ), 'feet in an inches' => test_zci( - '1 inch = 0.083 feet', + '1 inch = 0.0833 feet', structured_answer => make_answer({ markup_input => '1', raw_input => '1', from_unit => 'inch', - styled_output => '0.083', - raw_answer => '0.083', + styled_output => '0.0833', + raw_answer => '0.0833', to_unit => 'feet', physical_quantity => 'length' }) @@ -1237,13 +1237,13 @@ ddg_goodie_test( }) ), 'mm in inches' => test_zci( - '1 millimeter = 0.039 inches', + '1 millimeter = 0.0394 inches', structured_answer => make_answer({ markup_input => '1', raw_input => '1', from_unit => 'millimeter', - styled_output => '0.039', - raw_answer => '0.039', + styled_output => '0.0394', + raw_answer => '0.0394', to_unit => 'inches', physical_quantity => 'length' }) @@ -1359,13 +1359,13 @@ ddg_goodie_test( ), # Areas and volumes '100 square metres in hectares' => test_zci( - '100 square meters = 0.010 hectares', + '100 square meters = 0.0100 hectares', structured_answer => make_answer({ markup_input => '100', raw_input => '100', from_unit => 'square meters', - styled_output => '0.010', - raw_answer => '0.010', + styled_output => '0.0100', + raw_answer => '0.0100', to_unit => 'hectares', physical_quantity => 'area' }) @@ -1431,13 +1431,13 @@ ddg_goodie_test( }) ), '1 acre in square kilometers' => test_zci( - '1 acre = 0.004 square kilometers', + '1 acre = 0.00405 square kilometers', structured_answer => make_answer({ markup_input => '1', raw_input => '1', from_unit => 'acre', - styled_output => '0.004', - raw_answer => '0.004', + styled_output => '0.00405', + raw_answer => '0.00405', to_unit => 'square kilometers', physical_quantity => 'area' }) @@ -1684,13 +1684,13 @@ ddg_goodie_test( }) ), '1 acres in square kilometers' => test_zci( - '1 acre = 0.004 square kilometers', + '1 acre = 0.00405 square kilometers', structured_answer => make_answer({ markup_input => '1', raw_input => '1', from_unit => 'acre', - styled_output => '0.004', - raw_answer => '0.004', + styled_output => '0.00405', + raw_answer => '0.00405', to_unit => 'square kilometers', physical_quantity => 'area' }) @@ -2984,7 +2984,18 @@ ddg_goodie_test( physical_quantity => 'volume' }) ), - + '1 cup to gallons' => test_zci( + '1 us cup = 0.0625 us gallons', + structured_answer => make_answer({ + markup_input => '1', + raw_input => '1', + from_unit => 'us cup', + styled_output => '0.0625', + raw_answer => '0.0625', + to_unit => 'us gallons', + physical_quantity => 'volume' + }) + ), # Intentionally untriggered '5 inches in 5 meters' => undef,