Jump to page: 1 2
Thread overview
[phobos] Rational for review
Aug 28, 2010
David Simcha
Aug 28, 2010
Philippe Sigaud
Aug 28, 2010
Philippe Sigaud
Aug 28, 2010
David Simcha
Aug 28, 2010
Philippe Sigaud
Aug 28, 2010
David Simcha
Aug 28, 2010
David Simcha
Aug 28, 2010
David Simcha
August 27, 2010
  I've cleaned up/fixed the bit rot in my Rational library.  It's
available for review at:
http://dsource.org/projects/scrapple/browser/trunk/rational/rational.d?rev=785
.

Known issues:

1.  Due to bugs in BigInt (mainly 4742 http://d.puremagic.com/issues/show_bug.cgi?id=4742), BigInt instantiations don't play nicely with builtin integer instantiations. For example, this doesn't work:

auto a = rational(BigInt(1), 2) * rational(8, 7);

2.  I couldn't figure out how to handle the case of user-defined fixed-width integer types in the decimal conversion (opCast) function, so it just assumes non-builtin integer types are arbitrary precision. The biggest problem is lack of a way of introspecting whether the integer is fixed or arbitrary width and what its fixed width might be if it is, in fact, fixed.  The secondary problem is that I don't know of a good algorithm (though I'm sure I could find one if I tried) for converting fixed-width integers to floating point numbers in software. Arbitrary precision is much easier.

3.  There is a small amount of special case ad-hockery to make things work with std.bigint.BigInt.  I consider these bug workarounds.  In principle, everything should work with any user defined arbitrary precision integer if it overloads everything it's supposed to overload.
August 28, 2010
On Sat, Aug 28, 2010 at 02:48, David Simcha <dsimcha at gmail.com> wrote:

>  I've cleaned up/fixed the bit rot in my Rational library.  It's available
> for review at:
> http://dsource.org/projects/scrapple/browser/trunk/rational/rational.d?rev=785.
>

Let's give it a try.
First thing, it's not your faut, but:

import rational;
void main()
{
    auto r = rational(1,2); // error, finds module rational and not
rational.rational
}

This is going to be a PITA...

Let say from nom on, I prefix everything with rational.*

auto r = rational(1,2);
r = 1; // do not work.

Maybe you could add opAssign from integer numbers?

Next, 1/0. OK, it's correctly dealt with (Integer Divide By Zero Error)
But 0/1 botches. In fact, any rational that's zero creates a DBZ error. r-=
r, etc.
I guess it's a pb in simplify (454-455) or gcf (638), you should test for a
zero numerator or divisor

Now, for the code itself:
line 35: Maybe you should add %, %=, they are part of what I consider
'integer like'. You use them in gcf anyway

As an aside, isIntegerLike, the equivalent isFloatingPointLike and
defineOperators!( some string tuple) could be interesting additions to
std.traits.
I don't know what FP-like would be, maybe test for values between 0 and 1,
and test for NaN.

75: if you make it public, you should add a template constraint if(isIntegral!I1 && isIntegral!i2). The same for gcf at line 640 76: why * instead of +?

303: swap in invert. I like this!

307, 317 (opEqual, opCmp). Wikipedia uses denom1*num2 - denom2*num1 == 0 as the equivalence relation among rational numbers. Maybe this can be extended to opCmp ? Ah, you want to avoid overflow, I gather? OK, scratch this.

559: could toRational be a constructor? auto r = rational(PI, 1e-8);

638, 675: Maybe gcf/lcm could become part of std.numerics?

All in all, I like you code very much, it's very clean and readable. It's even organized the way I'd do it : first templates, then structs, then functions.


Some possible additions:
* an integerPart function or property (returning an Int) or casting as an
Int directly, 22/7 -> 3
* a fractional part function (ie 22/7 is ~3.14 -> 0.14) as a FP
* Accordingly,  floor/ceil functions could be interesting, unless you think
the user should use std.math.floor(cast(real)rat), which I could understand.
* Addendum (probably not a good idea): you can have infinity and NaN-like
values with 1/0, -1/0 and 0/0...

***
 2.  I couldn't figure out how to handle the case of user-defined
fixed-width integer types in the decimal conversion (opCast) function, so it
just assumes non-builtin integer types are arbitrary precision.  The biggest
problem is lack of a way of introspecting whether the integer is fixed or
arbitrary width and what its fixed width might be if it is, in fact, fixed.
 The secondary problem is that I don't know of a good algorithm (though I'm
sure I could find one if I tried) for converting fixed-width integers to
floating point numbers in software.  Arbitrary precision is much easier.
***

About converting fixed-width integer-like types, maybe these should provide
.min and .max properties?
That way you know the range of possible values and maybe it's then possible
to convert (I didn't think this through so I may be completly mistaken)

Good work David. My only pb is that you write code faster that I can read it, and don't let me any time to write some myself! It took me a week to read the recent additions in Phobos!


*goes back to cleaning his algebraic data types and type mimicry code*


Philippe

Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100828/aa769581/attachment-0001.html>
August 28, 2010
On Sat, 2010-08-28 at 16:24 +0200, Philippe Sigaud wrote:
> 
> 
> On Sat, Aug 28, 2010 at 02:48, David Simcha <dsimcha at gmail.com> wrote:
>          I've cleaned up/fixed the bit rot in my Rational library.
>          It's available for review at:
>          http://dsource.org/projects/scrapple/browser/trunk/rational/rational.d?rev=785 .
> 
> Let's give it a try.
> First thing, it's not your faut, but:
> 
> import rational;
> void main()
> {
>     auto r = rational(1,2); // error, finds module rational and not
> rational.rational
> }
> 
> This is going to be a PITA...

But it's only a problem when the module is called 'rational'.  If it becomes 'std.rational' or is incorporated in std.numeric, it won't be a problem anymore.

-Lars


August 28, 2010
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100828/508cb667/attachment-0001.html>
August 28, 2010
  On 8/28/2010 10:24 AM, Philippe Sigaud wrote:
> * Accordingly,  floor/ceil functions could be interesting, unless you think the user should use std.math.floor(cast(real)rat), which I could understand.

BTW, would you recommend free functions (consistent with std.math and overloadable with std.math after Bug 2972 http://d.puremagic.com/issues/show_bug.cgi?id=2972 gets fixed) or member functions (because that's usually the way you would do something like this if std.math hadn't already set a precedent to be consistent with)?

August 28, 2010
On Sat, Aug 28, 2010 at 16:34, Lars Tandle Kyllingstad <lars at kyllingen.net>wrote:


> > This is going to be a PITA...
>
> But it's only a problem when the module is called 'rational'.  If it becomes 'std.rational' or is incorporated in std.numeric, it won't be a problem anymore.
>

(head, meet palm)

Doh, you're right of course!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100828/46fc2d86/attachment.html>
August 28, 2010
On Sat, Aug 28, 2010 at 20:38, David Simcha <dsimcha at gmail.com> wrote:

>
> > Let say from nom on, I prefix everything with rational.
> Don't worry about module issues.  As Lars pointed out, the library will not be named rational if/when it's integrated into Phobos.  It will be std.rational or be included in std.numerics
>

 Yes, you're right.




>
> auto r = rational(1,2);
> r = 1; // do not work.
>
> Maybe you could add opAssign from integer numbers?
>
>
> I fixed this right after I sent out the request for comment, because I realized that not allowing it was a bit silly.  Unfortunately, I accidentally sent a link that pointed to a specific revision.  Here's a new link that updates will be reflected in: http://dsource.org/projects/scrapple/browser/trunk/rational/rational.d
>
>
Good.

line 76: isAssignable would be a good addition to std.traits.


>
> Next, 1/0. OK, it's correctly dealt with (Integer Divide By Zero Error)
> But 0/1 botches. In fact, any rational that's zero creates a DBZ error. r-=
> r, etc.
> I guess it's a pb in simplify (454-455) or gcf (638), you should test for a
> zero numerator or divisor
>
>
> I can't believe I forgot to test this edge case.  Fixed by simply testing for zero as a special case in simplify().
>

Put in some very basic unit tests :-)  0+0==0, 1-1==0, that kind of thing :)





>
>
> Now, for the code itself:
> line 35: Maybe you should add %, %=, they are part of what I consider
> 'integer like'. You use them in gcf anyway
>
>
> Good point.  Done.  Also added comparison.
>

Man, integer-like is beginning to be quite big.

What about adding ++ and -- ?

Btw, I'm against putting ++ and -- in Rational, but please do add opUnary!"+", opUnary!"-".



> As an aside, isIntegerLike, the equivalent isFloatingPointLike and
> defineOperators!( some string tuple) could be interesting additions to
> std.traits.
> I don't know what FP-like would be, maybe test for values between 0 and 1,
> and test for NaN.
>
>
> You may be right, but I'd rather wait until more user defined integer and floating point types are around to see exactly what such templates should require.
>

You're right. As of now, I see three traits:
isNumeric (ie, defines + - / * and is ordered: defines < > ==),
isIntegerLike(isNumeric, and % << >> <<< ++ --),
isFPLike(isNumeric, and (0.0+1.0)/2.0 is not zero)
As I'm no specialist of floating points, I'll let other decide.

So, there is also isOrdered or isComparable for opCmp and opEqual

Hmm, asking for NaN to be FP might not be a good idea: wasn't there some
plan to build a BigDecimal type at some point? I gather BigDecimal wouldn't
have NaN.
I tried to do one 2 years ago, built on BigInt+decimal point position. I
remember it to be awfully buggy :-)

I also tried to represent 'real' real numbers with a BigInt + an infinite
range (for the part after the .), but that was a mistake :)



>
> 75: if you make it public, you should add a template constraint if(isIntegral!I1 && isIntegral!i2). The same for gcf at line 640
>
>
> Good point.  Fixed.
>

I wasn't sure you wanted to make this public.



>   76: why * instead of +?
>
>
> No particular reason.  Any reasonable type should return the same type for either one.  I can't see why it would matter either way.
>

It shouldn't. That was just curiosity on my part. I'd have use an addition.



>
> 559: could toRational be a constructor? auto r = rational(PI, 1e-8);
>
>
>
> I'd rather leave it as a free function for a few reasons:
>
> 1.  In general the convention in Phobos is that non-trivial construction steps for structs are done in free functions.  Even though the reasons for that convention don't apply here, I'd rather follow it unless there's really a good reason to violate it.
>
> 2.  IIRC templated constructors are generally buggy, though I can't remember specifically how they're buggy.
>
> 3.  Lower case names are easier to type and read.
>
> 4.  It's what I already have written and I'm lazy. :-)
>
> I don't feel very strongly about this, though.  If you really feel strongly that it should be a constructor, though, and can explain why, then I'm willing to reconsider.
>
>
I meant a factory function, not a real constructor per se. See my example:
auto r = rational(PI, 1e-8);
It takes care of point 1, 2 and 3. As for 4, maybe just an alias would be
ok?

But I see in any case, the user has to provide the integer type she wants to use, so my example is not OK.



 * a fractional part function (ie 22/7 is ~3.14 -> 0.14) as a FP
>
>
> Ditto.
>

Thinking about it some more, maybe the fractional part should return a typeof(this): 22/7 -> 1/7. Not a float.


>
>  * Accordingly,  floor/ceil functions could be interesting, unless you
> think the user should use std.math.floor(cast(real)rat), which I could
> understand.
>
>
> Again, good idea.  Using std.math sucks because a major point of Rational is that it's supposed to work with arbitrary precision, and reals aren't arbitrary precision.
>


I could argue that floor or ceil are exactly when you get rid of this arbitrary precision, but to answer the question in your next post, I think these should be part of the rational module and be free functions: it makes the module self-supported. And having rational support in std math means it must in turn import the rational module. I'm against this.

In any case, people will probably import both at the same time...

I'm not clear on the subtle nuances between the integer part, the floor and the ceil for positive and negative Rationals, though.

See std.math: ceil, floor, nearbyInt, round, trunc! Awww.

The next question would be: what other free function? I'll add abs(), but
not much more. Maybe pow or opBinary!"^^" ?
I wouldn't add any trigonometric function.
sqrt is on the fence for me. Is there an algorithm to calculate the square
root of a rational apart from the Babylonian method?


>
>   * Addendum (probably not a good idea): you can have infinity and
> NaN-like values with 1/0, -1/0 and 0/0...
>
>
> Probably not.  I really despise NaNs in floating point code because they break fundamental mathematical axioms that appear to be common sense (such as x == x, x * 0 == 0, if !(x <= y) then x > y, and x < y || x == y || x > y).  For example, try making a sorting algorithm or a binary tree with floating point numbers if they may be NaNs.  I'd rather just leave it the way it is, where it throws if the denominator is zero.
>

So it's ditched then.

We might at one point need an integer-like type adding negative and positive infinity, if only to cleanly represent slices on infinite ranges.



>
> ***
>  2.  I couldn't figure out how to handle the case of user-defined
> fixed-width integer types in the decimal conversion (opCast) function, so it
> just assumes non-builtin integer types are arbitrary precision.  The biggest
> problem is lack of a way of introspecting whether the integer is fixed or
> arbitrary width and what its fixed width might be if it is, in fact, fixed.
>  The secondary problem is that I don't know of a good algorithm (though I'm
> sure I could find one if I tried) for converting fixed-width integers to
> floating point numbers in software.  Arbitrary precision is much easier.
> ***
>
> About converting fixed-width integer-like types, maybe these should provide
> .min and .max properties?
> That way you know the range of possible values and maybe it's then possible
> to convert (I didn't think this through so I may be completly mistaken)
>
>
> I think what I'm going to do here is just throw an exception iff the denominator has both the highest and lowest order bit set.  This is enough of a corner case in that it will only happen close to the limit of the largest denominator value that can be represented that I don't consider it a major limitation.  It's easily detectable because the numerator will never become bigger than the denominator by bit shifting iff either the numerator is zero or the denominator has its highest order bit set.  If the denominator's lowest order bit isn't set then I can shift the denominator right to make it not have its highest order bit set.
>

What's the pb with having a numerator bigger than the denominator? Sorry, I didn't read the conversion function carefully.



>
> If anyone has any better ideas, or considers this too severe a limitation, let me know.
>

Do that and we'll see how it goes.



>
>
>
> Good work David. My only pb is that you write code faster that I can read it, and don't let me any time to write some myself! It took me a week to read the recent additions in Phobos!
>
>
> This code has been around in some form for almost a year.  It's just that the proposal for a units library made me remember that I've been meaning to clean up all the bit rot, improve it and submit it for inclusion.
>

Seeing that you have time, talent and energy, I'll order a BigDecimal module :-)



>
>
>
> *goes back to cleaning his algebraic data types and type mimicry code*
>
>
> Great.  I look forward to when this code is ready.
>

No you don't :) It's full of string mixins, variadic templates, CT type
witchery, typetuples, objects hierarchies generated by CTFE and such. All in
all, it's a smorgasbord of D possibilities :)
But it's slowly coming together and the use is very easy.  I can already
imitate std.Tuple and std.Algebraic, make recursive types: lists and trees,
cyclic types (graphs?), imitate Haskell's Either and Maybe types, do
statically checked pattern matching on them, and create map/reduce
functions. So I'm not far from ADT in other languages that have them with
compiler support (Scala, Haskell, ML, F#...)
I still have to automate this last point (automatically generating a reduce
function on any recursive algebraic type), add variadic arguments (which
AFAICT no other language provide) and then code generalized algebraic
datatypes, the flagship of the most powerful functional languages: CAML and
Haskell :-)  Strangely, I see no difficulty *for now* in the last part.
In any case, even if I'm not sure this should be part of D standard library,
I'd be fun and good for PR to have them in a library somewhere.

As for type mimic it's nothing fancy but I'll try to post something soon, to restart the discussion on typedef once more.

Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100828/6777b74d/attachment-0001.html>
August 28, 2010
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20100828/2a5b9918/attachment.html>
August 28, 2010
Yes please.

Sent by shouting through my showerhead.

On Aug 28, 2010, at 4:22 PM, David Simcha <dsimcha at gmail.com> wrote:

> On 8/28/2010 4:22 PM, Philippe Sigaud wrote:
>>
>> line 76: isAssignable would be a good addition to std.traits.
>
> Yeah, will do unless anyone has any objections.
>
>>
>>
>>>
>>> Next, 1/0. OK, it's correctly dealt with (Integer Divide By Zero
>>> Error)
>>> But 0/1 botches. In fact, any rational that's zero creates a DBZ
>>> error. r-= r, etc.
>>> I guess it's a pb in simplify (454-455) or gcf (638), you should
>>> test for a zero numerator or divisor
>>
>> I can't believe I forgot to test this edge case.  Fixed by simply testing for zero as a special case in simplify().
>>
>> Put in some very basic unit tests :-)  0+0==0, 1-1==0, that kind of thing :)
>
> Did that already.  They pass.
>
>>
>>>
>>> Now, for the code itself:
>>> line 35: Maybe you should add %, %=, they are part of what I
>>> consider 'integer like'. You use them in gcf anyway
>>
>> Good point.  Done.  Also added comparison.
>>
>> Man, integer-like is beginning to be quite big.
>>
>> What about adding ++ and -- ?
>
> I don't need/use them, so there's no real reason to require them.
>
>>
>> Btw, I'm against putting ++ and -- in Rational, but please do add opUnary!"+", opUnary!"-".
>
> Will do, along with ^^.  These were left out as oversights, not for "good" reasons.
>
>>
>>> * a fractional part function (ie 22/7 is ~3.14 -> 0.14) as a FP
>>
>> Ditto.
>>
>> Thinking about it some more, maybe the fractional part should return a typeof(this): 22/7 -> 1/7. Not a float.
>
> Yea, this makes more sense.  If you want a float, you can always cast it.
>
>>
>>> * Accordingly,  floor/ceil functions could be interesting, unless you think the user should use std.math.floor(cast(real)rat), which I could understand.
>>
>> Again, good idea.  Using std.math sucks because a major point of Rational is that it's supposed to work with arbitrary precision, and reals aren't arbitrary precision.
>>
>>
>> I could argue that floor or ceil are exactly when you get rid of this arbitrary precision, but to answer the question in your next post, I think these should be part of the rational module and be free functions: it makes the module self-supported. And having rational support in std math means it must in turn import the rational module. I'm against this.
>>
>> In any case, people will probably import both at the same time...
>>
>> I'm not clear on the subtle nuances between the integer part, the floor and the ceil for positive and negative Rationals, though.
>>
>> See std.math: ceil, floor, nearbyInt, round, trunc! Awww.
>>
>> The next question would be: what other free function? I'll add abs (), but not much more. Maybe pow or opBinary!"^^" ?
>
> opBinary!"^^":  Yes.  pow():  I don't see the point.  Probably everyone writing generic math code nowadays will use ^^ instead of pow() because it's less typing and more readable.  Then again, pow() would be trivial to implement in terms of opBinary!"^^".
>
>> I wouldn't add any trigonometric function.
>
>> .
>> sqrt is on the fence for me. Is there an algorithm to calculate the
>> square root of a rational apart from the Babylonian method?
>
> I'm going to leave trig and sqrt out.  To me, the point of rationals is to allow calculations to be exact.  Functions where the result can be irrational don't make sense in this context.  You'd be better off just casting to real and then calling the std.math functions.
>
>>
>>> ***
>>>  2.  I couldn't figure out how to handle the case of user-defined
>>> fixed-width integer types in the decimal conversion (opCast)
>>> function, so it just assumes non-builtin integer types are
>>> arbitrary                     precision.  The biggest problem is
>>> lack of a way of introspecting whether the integer is fixed or
>>> arbitrary width and what its fixed width might be if it is, in
>>> fact, fixed.  The secondary problem is                     that I
>>> don't know of a good algorithm (though I'm sure I could find one
>>> if I tried) for converting fixed-width integers to floating point
>>> numbers in software.  Arbitrary precision is much easier.
>>> ***
>>>
>>> About converting fixed-width integer-like types, maybe these
>>> should provide .min and .max properties?
>>> That way you know the range of possible values and maybe it's then
>>> possible to convert (I didn't think this through so I may be
>>> completly mistaken)
>>
>> I think what I'm going to do here is just throw an exception iff the denominator has both the highest and lowest order bit set. This is enough of a corner case in that it will only happen close to the limit of the largest denominator value that can be represented that I don't consider it a major limitation.  It's easily detectable because the numerator will never become bigger than the denominator by bit shifting iff either the numerator is zero or the denominator has its highest order bit set.  If the denominator's lowest order bit isn't set then I can shift the denominator right to make it not have its highest order bit set.
>>
>> What's the pb with having a numerator bigger than the denominator? Sorry, I didn't read the conversion function carefully.
>
> The way the function works involves bit shifting the numerator left until it's bigger than the denominator.  If the denominator has its highest order bit occupied, no amount of shifting will ever make the numerator bigger.
>>
>> This code has been around in some form for almost a year.  It's just that the proposal for a units library made me remember that I've been meaning to clean up all the bit rot, improve it and submit it for inclusion.
>>
>> Seeing that you have time, talent and energy, I'll order a BigDecimal module :-)
>
> I'd love one, but I haven't the slightest clue how to write one and have several hacking projects that I need to finish/start before even considering it.
>
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
August 28, 2010
  Yes please what?  isAssignable?  The whole module?  I'm confused.

On 8/28/2010 6:07 PM, Andrei Alexandrescu wrote:
> Yes please.
>
> Sent by shouting through my showerhead.
>
> On Aug 28, 2010, at 4:22 PM, David Simcha <dsimcha at gmail.com> wrote:
>
>> On 8/28/2010 4:22 PM, Philippe Sigaud wrote:
>>>
>>> line 76: isAssignable would be a good addition to std.traits.
>>
>> Yeah, will do unless anyone has any objections.
>>
>>>
>>>
>>>>
>>>> Next, 1/0. OK, it's correctly dealt with (Integer Divide By Zero
>>>> Error)
>>>> But 0/1 botches. In fact, any rational that's zero creates a DBZ
>>>> error. r-= r, etc.
>>>> I guess it's a pb in simplify (454-455) or gcf (638), you should
>>>> test for a zero numerator or divisor
>>>
>>> I can't believe I forgot to test this edge case.  Fixed by simply testing for zero as a special case in simplify().
>>>
>>> Put in some very basic unit tests :-)  0+0==0, 1-1==0, that kind of thing :)
>>
>> Did that already.  They pass.
>>
>>>
>>>>
>>>> Now, for the code itself:
>>>> line 35: Maybe you should add %, %=, they are part of what I
>>>> consider 'integer like'. You use them in gcf anyway
>>>
>>> Good point.  Done.  Also added comparison.
>>>
>>> Man, integer-like is beginning to be quite big.
>>>
>>> What about adding ++ and -- ?
>>
>> I don't need/use them, so there's no real reason to require them.
>>
>>>
>>> Btw, I'm against putting ++ and -- in Rational, but please do add opUnary!"+", opUnary!"-".
>>
>> Will do, along with ^^.  These were left out as oversights, not for "good" reasons.
>>
>>>
>>>> * a fractional part function (ie 22/7 is ~3.14 -> 0.14) as a FP
>>>
>>> Ditto.
>>>
>>> Thinking about it some more, maybe the fractional part should return a typeof(this): 22/7 -> 1/7. Not a float.
>>
>> Yea, this makes more sense.  If you want a float, you can always cast it.
>>
>>>
>>>> * Accordingly,  floor/ceil functions could be interesting, unless you think the user should use std.math.floor(cast(real)rat), which I could understand.
>>>
>>> Again, good idea.  Using std.math sucks because a major point of Rational is that it's supposed to work with arbitrary precision, and reals aren't arbitrary precision.
>>>
>>>
>>> I could argue that floor or ceil are exactly when you get rid of this arbitrary precision, but to answer the question in your next post, I think these should be part of the rational module and be free functions: it makes the module self-supported. And having rational support in std math means it must in turn import the rational module. I'm against this.
>>>
>>> In any case, people will probably import both at the same time...
>>>
>>> I'm not clear on the subtle nuances between the integer part, the floor and the ceil for positive and negative Rationals, though.
>>>
>>> See std.math: ceil, floor, nearbyInt, round, trunc! Awww.
>>>
>>> The next question would be: what other free function? I'll add abs(), but not much more. Maybe pow or opBinary!"^^" ?
>>
>> opBinary!"^^":  Yes.  pow():  I don't see the point.  Probably everyone writing generic math code nowadays will use ^^ instead of pow() because it's less typing and more readable.  Then again, pow() would be trivial to implement in terms of opBinary!"^^".
>>
>>> I wouldn't add any trigonometric function.
>>
>>> .
>>> sqrt is on the fence for me. Is there an algorithm to calculate the
>>> square root of a rational apart from the Babylonian method?
>>
>> I'm going to leave trig and sqrt out.  To me, the point of rationals is to allow calculations to be exact.  Functions where the result can be irrational don't make sense in this context.  You'd be better off just casting to real and then calling the std.math functions.
>>
>>>
>>>> ***
>>>>  2.  I couldn't figure out how to handle the case of user-defined
>>>> fixed-width integer types in the decimal conversion (opCast)
>>>> function, so it just assumes non-builtin integer types are
>>>> arbitrary                     precision.  The biggest problem is
>>>> lack of a way of introspecting whether the integer is fixed or
>>>> arbitrary width and what its fixed width might be if it is, in
>>>> fact, fixed.  The secondary problem is                     that I
>>>> don't know of a good algorithm (though I'm sure I could find one if
>>>> I tried) for converting fixed-width integers to floating point
>>>> numbers in software.  Arbitrary precision is much easier.
>>>> ***
>>>>
>>>> About converting fixed-width integer-like types, maybe these should
>>>> provide .min and .max properties?
>>>> That way you know the range of possible values and maybe it's then
>>>> possible to convert (I didn't think this through so I may be
>>>> completly mistaken)
>>>
>>> I think what I'm going to do here is just throw an exception iff the denominator has both the highest and lowest order bit set.  This is enough of a corner case in that it will only happen close to the limit of the largest denominator value that can be represented that I don't consider it a major limitation.  It's easily detectable because the numerator will never become bigger than the denominator by bit shifting iff either the numerator is zero or the denominator has its highest order bit set.  If the denominator's lowest order bit isn't set then I can shift the denominator right to make it not have its highest order bit set.
>>>
>>> What's the pb with having a numerator bigger than the denominator? Sorry, I didn't read the conversion function carefully.
>>
>> The way the function works involves bit shifting the numerator left until it's bigger than the denominator.  If the denominator has its highest order bit occupied, no amount of shifting will ever make the numerator bigger.
>>>
>>> This code has been around in some form for almost a year.  It's just that the proposal for a units library made me remember that I've been meaning to clean up all the bit rot, improve it and submit it for inclusion.
>>>
>>> Seeing that you have time, talent and energy, I'll order a BigDecimal module :-)
>>
>> I'd love one, but I haven't the slightest clue how to write one and have several hacking projects that I need to finish/start before even considering it.
>>
>> _______________________________________________
>> phobos mailing list
>> phobos at puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/phobos
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
>

« First   ‹ Prev
1 2