October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | On 01/10/13 08:26, ilya-stromberg wrote: > Note that denumerator must be allways positive (> 0). > But numerator can be positive, zero or negative, and can be bigger than > denumerator. > It means that we can use different types for numerator and denumerator: Seems an overcomplication for me, and it doesn't save you from denominator == 0, so it doesn't get you out of any checks. > We have BigUint in Phobos, but it's private. Interesting. Any particular reason? (I suppose the nature of BigInt is that you don't need to worry about signed/unsigned distinction because there is no range limit.) > Also, if we need only positive rationals, we can use unsigned types for numerator: Yes, but you can already get that as is by Rational!(UnsignedTypeOfChoice) :-) |
October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rushton Wakeling | On Tuesday, 1 October 2013 at 08:02:12 UTC, Joseph Rushton Wakeling wrote: > On 01/10/13 08:26, ilya-stromberg wrote: >> Note that denumerator must be allways positive (> 0). >> But numerator can be positive, zero or negative, and can be bigger than >> denumerator. >> It means that we can use different types for numerator and denumerator: > > Seems an overcomplication for me, and it doesn't save you from denominator == 0, so it doesn't get you out of any checks. It's from a mathematics: http://ru.wikipedia.org/wiki/%D0%94%D1%80%D0%BE%D0%B1%D1%8C_%28%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%29 Numerator must be integer (..., -2, -1, 0, 1, 2, ...): http://en.wikipedia.org/wiki/Integer Denumerator must be natural number (1, 2, 3, ...): http://en.wikipedia.org/wiki/Natural_number Note that english wikipedia says that denumerator is integer not equal to zero: http://en.wikipedia.org/wiki/Rational_number It's interesting: have we got 2 different mathematics, or it's just mistake in wikipedia? I didn't read any english mathematics books, but the GMP library agree with me: "All rational arithmetic functions assume operands have a canonical form, and canonicalize their result. The canonical from means that the denominator and the numerator have no common factors, and that the denominator is positive. Zero has the unique representation 0/1." http://gmplib.org/manual/Rational-Number-Functions.html#Rational-Number-Functions May be you are rigth and store numerator and denumerator type is too complex, but it have some benefits. For example, we can save some memory with BigUint type because it doesn't store unnecessary sign. > >> We have BigUint in Phobos, but it's private. > > Interesting. Any particular reason? (I suppose the nature of BigInt is that you don't need to worry about signed/unsigned distinction because there is no range limit.) I don't know, I just found it in source code: https://github.com/D-Programming-Language/phobos/blob/master/std/bigint.d module std.bigint; private import std.internal.math.biguintcore; struct BigInt { private: BigUint data; // BigInt adds signed arithmetic to BigUint. bool sign = false; //... } > >> Also, if we need only positive rationals, we can use unsigned types for numerator: > > Yes, but you can already get that as is by Rational!(UnsignedTypeOfChoice) :-) |
October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
On 28/09/13 13:15, Joseph Rushton Wakeling wrote: > Well, obviously. Actually I'm not unhappy with David's name per se but with the > idea of being inconsistent with how other libraries name these methods. > Boost.Rational uses the full names, I'll have a look around and see how other > libraries name them and whether there is consensus. Boost.Rational, Python's numbers.Rational, Ruby's Rational, Haskell's Ratio, and both Common Lisp and Scheme's in-built rational number support all use numerator and denominator for their corresponding method names: http://www.boost.org/doc/libs/1_54_0/libs/rational/rational.html#Numerator%20and%20Denominator http://docs.python.org/2/library/numbers.html#numbers.Rational http://docs.python.org/3/library/numbers.html#numbers.Rational http://www.ruby-doc.org/core-2.0.0/Rational.html http://www.haskell.org/onlinereport/ratio.html http://www.lispworks.com/documentation/lw50/CLHS/Body/f_numera.htm http://www.franz.com/support/documentation/current/ansicl/dictentr/numerato.htm http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-2.html#node_toc_node_sec_11.7.1 I also came across a Rational.java here which follows the same convention, but I don't know how "official" this library is: http://introcs.cs.princeton.edu/java/32class/Rational.java.html ... while this C# class uses Numerator and Denominator for the public method names (hey, it's C#, they have to be different, even if it's only by a capital letter:-) http://exif-utils.googlecode.com/svn/trunk/ExifUtils/ExifUtils/Rational.cs The one standout I came across was Julia, which uses "num" and "den": http://docs.julialang.org/en/latest/manual/complex-and-rational-numbers/#rational-numbers ... and also implements an operator // to indicate rational division, which looks nice at first glance and then had me thinking, "Oh no, many bugs will come from this ..." In summary, I think we have other-language consensus here, and I'm going to make the switch to "numerator", "denominator" as the public method names. Objections can always be brought up at review time :-) |
October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | On 01/10/13 10:35, ilya-stromberg wrote: > It's from a mathematics: > http://ru.wikipedia.org/wiki/%D0%94%D1%80%D0%BE%D0%B1%D1%8C_%28%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%29 > > Numerator must be integer (..., -2, -1, 0, 1, 2, ...): > http://en.wikipedia.org/wiki/Integer > Denumerator must be natural number (1, 2, 3, ...): > http://en.wikipedia.org/wiki/Natural_number I'm fully aware of the maths of it. However, bear in mind that (i) m/(-n) is also a rational number, and that std.rational needs to support that case -- it's just that by convention in maths when we have m/(-n) we rewrite that as -m/n. (ii) enforcing that the denominator is an unsigned type doesn't actually make anything simpler internally because you still have to check that the denominator is > 0, and now you have to deal with the hassle of considering _two_ internal integer types with all the consequent issues of conversion, arithmetic etc. > Note that english wikipedia says that denumerator is integer not equal to zero: > http://en.wikipedia.org/wiki/Rational_number > It's interesting: have we got 2 different mathematics, or it's just mistake in > wikipedia? I didn't read any english mathematics books, but the GMP library > agree with me: > "All rational arithmetic functions assume operands have a canonical form, and > canonicalize their result. The canonical from means that the denominator and the > numerator have no common factors, and that the denominator is positive. Zero has > the unique representation 0/1." > http://gmplib.org/manual/Rational-Number-Functions.html#Rational-Number-Functions > > May be you are rigth and store numerator and denumerator type is too complex, > but it have some benefits. For example, we can save some memory with BigUint > type because it doesn't store unnecessary sign. We don't have any mathematical disagreement, it's merely that using two different types for numerator and denominator leads to unnecessary complexity for no meaningful gain. Re: BigInt -- how much memory do you think you're saving by eliminating signed-ness, compared to the typical anticipated size of a BigInt? BigInt itself is just a BigUInt plus a bool :-) > I don't know, I just found it in source code: > https://github.com/D-Programming-Language/phobos/blob/master/std/bigint.d It's because to implement a big integer you need to store 2 things: (i) the magnitude (absolute value) of the number, which is what BigUInt is there for; (ii) the sign of the number, which is just a boolean true/false == +/-. Because the type has (theoretically) no limits to its range, there's no point in making public the "unsigned" type, because you don't gain anything by this. For built-in integer types it matters because each unique value in the memory corresponds to a unique integer value, so you have constrained range and having an unsigned type doubles the upper range of the type. Compare to floating-point numbers where again the signed-ness is a single bit and so there's no gain to having an unsigned floating-point type. |
October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
On 01/10/13 11:07, Joseph Rushton Wakeling wrote: > In summary, I think we have other-language consensus here, and I'm going to make > the switch to "numerator", "denominator" as the public method names. Objections > can always be brought up at review time :-) https://github.com/WebDrake/Rational/issues/9 ... fixed by: https://github.com/WebDrake/Rational/commit/69efbaee6bfec9b3cad4192b159cfbbb1dd70711 |
October 01, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ilya-stromberg | On Tue, Oct 01, 2013 at 08:26:49AM +0200, ilya-stromberg wrote: > On Monday, 30 September 2013 at 18:01:29 UTC, Joseph Rushton Wakeling wrote: > >On 30/09/13 19:39, Joseph Rushton Wakeling wrote: > >>... although the new gcf will fail if passed immutable/const BigInts. > > > >On this note: http://d.puremagic.com/issues/show_bug.cgi?id=11148 > > > >I had to tweak CommonInteger to handle immutable/const BigInts, and I'm not sure whether this was done correctly, although it seems to be largely in line with how CommonType works. > > Note that denumerator must be allways positive (> 0). > But numerator can be positive, zero or negative, and can be bigger > than denumerator. > It means that we can use different types for numerator and > denumerator: [...] This is needlessly complex. We should just use signed types for both numerator and denominator, and handle sign by a canonicalization operation (canonicalization is already needed for reducing the fraction to its lowest terms anyway, and if gcd is implemented appropriately, it will return a number of appropriate sign to cancel out the negative sign in the denominator (or numerator), so this doesn't even need to be a separate check). T -- A computer doesn't mind if its programs are put to purposes that don't match their names. -- D. Knuth |
October 02, 2013 Re: std.rational? | ||||
---|---|---|---|---|
| ||||
On 01/10/13 16:49, H. S. Teoh wrote:
> This is needlessly complex. We should just use signed types for both
> numerator and denominator, and handle sign by a canonicalization
> operation (canonicalization is already needed for reducing the fraction
> to its lowest terms anyway, and if gcd is implemented appropriately, it
> will return a number of appropriate sign to cancel out the negative sign
> in the denominator (or numerator), so this doesn't even need to be a
> separate check).
That's how it's done. But your remark made me realize that correction of the signs is not checked in the unittests, so I've added a couple such checks. :-)
|
Copyright © 1999-2021 by the D Language Foundation