More on the rational Class


Andrew Dalke did a few tests of my rational number library (thanks) and I thought it deserved a post of its own.

The first links to code in the function float_as_integer_ratio_impl(), which is the C implementation of the Python method as_integer_ratio() …

OK, I found it.  Yeah, I tried to use frexp(); but I tried to do some bit twidling to get the mastissa bits as an integer and that was a big mistake.  It’s easy once you know how to do it. 😎

I’ll add something like this to my rational class; but I’m not sure yet whether I want to make it only for FLT_RADIX == 2 and whether I want to allow the user to do something less than an exact conversion, falling back on the continued fractions routine if I need to.

I wrote a quick and dirty program to do the tests mentioned in the comment and compiled it:

– for Windows using an ancient Microsoft compiler which doesn’t conform even to C++11 (although it has rvalue references and type traits templates which is enough for it to get through my bignum stuff), and with a long double that’s just a double.

– for Linux using a somewhat more up-to-date GCC (C++14 at least), and with a bigger long double.

I got two different sets of results (Windows, Linux), possibly due to differences in the long double format.

– The Windows version had no trouble with either 0.0869406496067503 or 1.1100695288645402e-29, but it failed on 0.9999999999999999.

– The Linux version failed on both 0.0869406496067503 and 1.1100695288645402e-29, but it worked on 0.9999999999999999.

– Both failed on nextafter(1,0).

… 1.1100695288645402e-29 gives a “Can’t convert NaNs or infinities to bigint” because the
val0 = 1.0 / (val0  static_cast(int0)); step results in an inf.

(That should be static_cast<long double>(int0)…either WordPress or the browser itself thought that the <long double> was an unrecognized HTML tag.)

My Linux version reports that as well.  That’s a bug in my code which I’ll have to figure out if I decide to keep the continued fractions around for support of either FLT_RADIX != 2 or inexact conversions.

I urge you to look towards an existing library if all you need is SQL interoperability.

Actually, what I need is to keep my mind active in my retirement. 😎

There are some third-party database access libraries out there; but they look to me like they were written by teenagers sitting in their basements going, “Cool!”; and I’m not sure that they scale up to real-world applications.  For example, there’s one called SOCI that actually tries to make database tables act like iostreams.

Also, I think I can make my library act like a Web service client as well, and maybe even access the cloud.  We’ll see…

Comments

  1. xohjoh2n says

    I noticed that on the previous post too:

    I urge you to look towards an existing library if all you need is SQL interoperability.

    That or equivalent gets said a lot, and within some contexts, at some times, it has a certain amount of merit to it. But people who say that, and especially those that treat it as an inviolable rule, never seem to be able to say where these existing libraries come from…

  2. Andrew Dalke says

    xohjoh2n@1, I haven’t done C++ since the 1990s, but pointed already pointed to the Python source, which has bigint, decimal, and rational data types. The hardest part, IMO, is not the API per se but figuring out which operations are needed, and implementing them both numerically correct and performant. Python’s equivalent to bigint multiplication, for example, switches to the Karatsuba algorithm for big enough values.

    The corresponding implementations in Python, the GNU Multiple Precision Arithmetic Library (which I’ve also used), or Postgres seem like useful sources, if not for source code then as pointers to approaches, a source of test cases, or as a way to cross-check results. The GMP has a C++ API, and Boost has three rational implementations; one native, one based on GMP, and another using LibTomMath. For decimal math see https://speleotrove.com/decimal/ which links to several C++ sources, mostly presenting a more C++-like interface on top of the IBM decNumber reference implementation.

    I trust I have given enough examples?

    I thought one possibility for this work was to lead to a WG21 technical specification. That’s certainly a neat goal for a retirement project! I just don’t see most people wanting to use this implementation given the ones I pointed to which have more features and are better tested and better known. I assume the database access API will be templated to allow other numeric implementations. If that’s the case, I still think it’s more convincing to focus on the database API rather than deal with numerical issues and support the range of functionality I think people generally expect from these types.

    If the goal is to have a chance to implement some of relevant algorithms from Knuth then that’s also a great retirement project! I still think cross-checking with existing implementations is a way to double-check that one’s mind is not only active, but on the right track. 🙂

  3. billseymour says

    Andrew Dalke, thanks for your comments.  They’re most informative.

    I’ll check out the GMP and the decimal stuff at speleotrove.com to see if they have types I can use.  If either has a decimal type with a precision of at least 38 decimal digits and with a scale, the number of digits to the right of the decimal point, that can be set at run time, that solves my database access library problem.

    I’ll also look for an unbounded integer that I can use as the numerator and denominator in my rational number, although I’ll still have the issue of converting from a floating point type to rational.

    But note that I’m deliberately not looking at anyone else’s source code because of copyright issues.  Even open-source code can come with a license that’s viral (the GPL comes easily to mind).

    I just don’t see most people wanting to use this implementation given the ones I pointed to which have more features and are better tested and better known.

    That’s certainly the case for folks who are doing serious numerical work, but they probably already do and don’t need any help from me.

    I thought one possibility for this work was to lead to a WG21 technical specification.

    Back in 2012, at a meeting in Kona, it was proposed that we publish a “Numbers TS” with things like fixed-point binary types and so forth.  I raised my hand and said that I had a rational number type that we might want to include, and N3363 was my first proposal.  That eventually morphed into P1889R1 §7.  Interest in such a TS has waned, though; and it’s no longer in the works.

    At a meeting in Portland later in that year, I proposed a database access library; and it was agreed that we’d set up a study group for that which I chaired.  Unfortunately, I developed some medical issues and the database stuff died on the vine.

    My programming experience for the last 30 years or so has been in good old “business data processing”, so that’s what I know most about.  That would never be more that a niche market for C++, though; so I don’t expect any of my post-retirement work to make it into any document that WG21 would publish.

    Update re the rational number:  I implemented an exact conversion from floating point types using frexp() and it works just fine.  I’ve even generalized it to work for any value of FLT_RADIX (although I don’t have access to any system where FLT_RADIX != 2 to test it on).  Unfortunately, it generates humongous numerators and denominators which I wouldn’t want to inflict on users; so I’ll stick with the continued fractions algorithm and let users opt in to the exact conversion business.

    While testing it on my Linux box using the values from your previous comment, I turned up a bug in my bigint division.  I’ll try to fix that tomorrow.

Leave a Reply

Your email address will not be published. Required fields are marked *