Skip to content
This repository has been archived by the owner on Oct 15, 2022. It is now read-only.

Commit

Permalink
Conversions: Improving result aesthetics (#3988)
Browse files Browse the repository at this point in the history
* Conversions: User feedback has indicated a preference for 3 sig figs for small(ish) results: #3984

* Conversions: Introducing the ability to have significant figures rather than decimal places for numbers <1

* Conversions: The reality is users want to see decimal places for 'normal numbers' (1,765.432 for example) but sig figs for something around 1 so that fractions can be expressed (0.0625 for example)

* Conversions: Bringing tests inline with 3 SF for results < 1; this is more aesthetically pleasing in my opinion
  • Loading branch information
mintsoft authored and moollaza committed Mar 8, 2017
1 parent 2117155 commit 95c8c84
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 36 deletions.
19 changes: 11 additions & 8 deletions lib/DDG/Goodie/Conversions.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -41,10 +42,11 @@ my $question_prefix = qr/(?<prefix>convert|what (?:is|are|does)|how (?:much|many
my $factor_re = join('|', ('a', 'an', number_style_regex()));
my $guard = qr/^(?<question>$question_prefix)\s?(?<left_num>$factor_re*)\s?(?<left_unit>$keys)\s(?<connecting_word>in|to|into|(?:in to)|from)?\s?(?<right_num>$factor_re*)\s?(?:of\s)?(?<right_unit>$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 {
Expand Down Expand Up @@ -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),
Expand All @@ -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);
Expand Down
67 changes: 39 additions & 28 deletions t/Conversions.t
Original file line number Diff line number Diff line change
Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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'
})
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 95c8c84

Please sign in to comment.