diff options
author | Karl Williamson <khw@cpan.org> | 2015-04-01 10:06:45 -0600 |
---|---|---|
committer | Karl Williamson <khw@cpan.org> | 2015-06-05 17:13:32 -0600 |
commit | 08f253eef6cd5c4f1c67f7336b0ba302d2c66bb0 (patch) | |
tree | 6170ff45341c213b90b3f0b7c3625783945e829a /lib | |
parent | 869a96128d21fb7bfc6989e285158f95e53c8971 (diff) | |
download | perl-08f253eef6cd5c4f1c67f7336b0ba302d2c66bb0.tar.gz |
mktables: Reduce input fractions to lowest terms
It turns out that the rational numbers furnished by the Unicode data are
not guaranteed to be in lowest terms. Version 8 is the first version
that has them this way. Add code to reduce them in preparation for that
release.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/unicore/mktables | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/lib/unicore/mktables b/lib/unicore/mktables index 8a4100c69f..bd312c4cdd 100644 --- a/lib/unicore/mktables +++ b/lib/unicore/mktables @@ -11162,8 +11162,10 @@ END $fields[$NUMERIC_TYPE_OTHER_DIGIT] = 'Numeric'; # Rationals require extra effort. - register_fraction($fields[$NUMERIC]) - if $fields[$NUMERIC] =~ qr{/}; + if ($fields[$NUMERIC] =~ qr{/}) { + reduce_fraction(\$fields[$NUMERIC]); + register_fraction($fields[$NUMERIC]) + } } } @@ -12201,6 +12203,50 @@ sub register_fraction($) { return; } +sub gcd($$) { # Greatest-common-divisor; from + # http://en.wikipedia.org/wiki/Euclidean_algorithm + my ($a, $b) = @_; + + use integer; + + while ($b != 0) { + my $temp = $b; + $b = $a % $b; + $a = $temp; + } + return $a; +} + +sub reduce_fraction($) { + my $fraction_ref = shift; + + # Reduce a fraction to lowest terms. The Unicode data may be reducible, + # hence this is needed. The argument is a reference to the + # string denoting the fraction, which must be of the form: + if ($$fraction_ref !~ / ^ (-?) (\d+) \/ (\d+) $ /ax) { + Carp::my_carp_bug("Non-fraction input '$$fraction_ref'. Unchanged"); + return; + } + + my $sign = $1; + my $numerator = $2; + my $denominator = $3; + + use integer; + + # Find greatest common divisor + my $gcd = gcd($numerator, $denominator); + + # And reduce using the gcd. + if ($gcd != 1) { + $numerator /= $gcd; + $denominator /= $gcd; + $$fraction_ref = "$sign$numerator/$denominator"; + } + + return; +} + sub filter_numeric_value_line { # DNumValues contains lines of a different syntax than the typical # property file: @@ -12225,7 +12271,9 @@ sub filter_numeric_value_line { $_ = ""; return; } + reduce_fraction(\$fields[3]) if $fields[3] =~ qr{/}; $rational = $fields[3]; + $_ = join '; ', @fields[ 0, 3 ]; } else { |