[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [sc-users] Conversion decimal into fractional
Here's a better hack for you. It represents the
numbers internally as floats (because it's silly to do
otherwise), but this class displays its value as a
fraction, unless the value is irrational.
Doing math on instances of this class will be slower,
because of the extra dispatches involved.
I've now spent as much time as I can afford on this
problem. I will leave it as the proverbial "exercise
for the reader" to add additional features (such as, a
method to get the numerator only, or the denominator,
or isRational which would output true if a denominator
can be found).
1 /% 2 // alternate division operator to create a
frac
1/2
a = Array.fill(8, { |i| (i+4) /% (i+3) });
[ 4/3, 5/4, 6/5, 7/6, 8/7, 9/8, 10/9, 11/10 ]
a.sum
23761/2520
a.sum.asFloat
9.4289682539683
// regular division produces decimals
b = b = Array.fill(8, { |i| (i+4) / (i+3) });
[ 1.3333333333333, 1.25, 1.2, 1.1666666666667,
1.1428571428571, 1.125, 1.1111111111111, 1.1 ]
b.asRational // convert to fractions
[ 4/3, 5/4, 6/5, 7/6, 8/7, 9/8, 10/9, 11/10 ]
a * 2
[ 8/3, 5/2, 12/5, 7/3, 16/7, 9/4, 20/9, 11/5 ]
a + 0.45
[ 107/60, 17/10, 33/20, 97/60, 223/140, 63/40,
281/180, 31/20 ]
b = a + sqrt(2) // don't estimate frac for
irrationals
[ 2.7475468957064, 2.6642135623731, 2.6142135623731,
2.5808802290398, 2.5570707052302, 2.5392135623731,
2.5253246734842, 2.5142135623731 ]
c = b - sqrt(2) // but the class remains Rational
[ 4/3, 5/4, 6/5, 7/6, 8/7, 9/8, 10/9, 11/10 ]
1.0245.asRational
2049/2000
// evaluating this string results in the original
// Array of Rationals
a.asCompileString
[ 4/%3, 5/%4, 6/%5, 7/%6, 8/%7, 9/%8, 10/%9, 11/%10 ]
hjh
=====
____ James Harkins /// dewdrop world
\ / jamshark70@xxxxxxxxx
\/ http://www.dewdrop-world.net
"... love and hot pants, peace, harmony..."
-- Dick Lee, Hot Pants: The Musical
+ SimpleNumber {
asRational { ^Rational.new(this) }
/% { |that| ^Rational(this.asFloat / that) }
}
+ Float {
/% { |that| ^Rational(this / that) }
}
+ Collection {
asRational {
^this.collect({ |item| item.asRational })
}
}
Rational : AbstractFunction {
var <value;
*new { |value| ^super.new.value_(value) }
*newFrom { |value| ^super.new.value_(value) }
value_ { |v| v.isNumber.if({ value = v },
{ MethodError("Value of a Rational must be a number", this).throw })
}
composeUnaryOp { arg aSelector;
^value.perform(aSelector).asRational
}
composeBinaryOp { arg aSelector, operand, adverb;
^value.perform(aSelector, operand, adverb).asRational
}
reverseComposeBinaryOp { arg aSelector, something, adverb;
^something.perform(aSelector, value, adverb).asRational
}
composeNAryOp { arg aSelector, anArgList;
^value.perform(aSelector, *anArgList).asRational
}
asRational { ^this }
asFloat { ^value }
asInteger { ^value.asInteger }
asString {
var denom;
((denom = value.fuzzygcd(1, 0.0001, 100)).notNil
and: { denom != 1 })
.if({
^(value * (denom = denom.reciprocal.round)).asString ++ "/" ++ denom
}, {
^value.asString
});
}
asCompileString {
var denom;
((denom = value.fuzzygcd(1, 0.0001, 100)).notNil
and: { denom != 1 })
.if({
^(value * (denom = denom.reciprocal.round)).asString ++ "/%" ++ denom
}, {
^"Rational(" ++ value.asCompileString ++ ")"
});
}
printOn { |stream| stream << this.asString }
storeOn { |stream| stream << this.asCompileString }
}