/[dtapublic]/projs/emts/trunk/src/lib_c/c_datd/gmp_rats.c
ViewVC logotype

Diff of /projs/emts/trunk/src/lib_c/c_datd/gmp_rats.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

sf_code/esrgpcpj/shared/c_datd/gmp_rats.c revision 25 by dashley, Sat Oct 8 06:43:03 2016 UTC projs/trunk/shared_source/c_datd/gmp_rats.c revision 90 by dashley, Sun Dec 4 16:14:46 2016 UTC
# Line 1  Line 1 
 // $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/c_datd/gmp_rats.c,v 1.10 2001/08/16 19:49:40 dtashley Exp $  
   
 //--------------------------------------------------------------------------------  
 //Copyright 2001 David T. Ashley  
 //-------------------------------------------------------------------------------------------------  
 //This source code and any program in which it is compiled/used is provided under the GNU GENERAL  
 //PUBLIC LICENSE, Version 3, full license text below.  
 //-------------------------------------------------------------------------------------------------  
 //                    GNU GENERAL PUBLIC LICENSE  
 //                       Version 3, 29 June 2007  
 //  
 // Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>  
 // Everyone is permitted to copy and distribute verbatim copies  
 // of this license document, but changing it is not allowed.  
 //  
 //                            Preamble  
 //  
 //  The GNU General Public License is a free, copyleft license for  
 //software and other kinds of works.  
 //  
 //  The licenses for most software and other practical works are designed  
 //to take away your freedom to share and change the works.  By contrast,  
 //the GNU General Public License is intended to guarantee your freedom to  
 //share and change all versions of a program--to make sure it remains free  
 //software for all its users.  We, the Free Software Foundation, use the  
 //GNU General Public License for most of our software; it applies also to  
 //any other work released this way by its authors.  You can apply it to  
 //your programs, too.  
 //  
 //  When we speak of free software, we are referring to freedom, not  
 //price.  Our General Public Licenses are designed to make sure that you  
 //have the freedom to distribute copies of free software (and charge for  
 //them if you wish), that you receive source code or can get it if you  
 //want it, that you can change the software or use pieces of it in new  
 //free programs, and that you know you can do these things.  
 //  
 //  To protect your rights, we need to prevent others from denying you  
 //these rights or asking you to surrender the rights.  Therefore, you have  
 //certain responsibilities if you distribute copies of the software, or if  
 //you modify it: responsibilities to respect the freedom of others.  
 //  
 //  For example, if you distribute copies of such a program, whether  
 //gratis or for a fee, you must pass on to the recipients the same  
 //freedoms that you received.  You must make sure that they, too, receive  
 //or can get the source code.  And you must show them these terms so they  
 //know their rights.  
 //  
 //  Developers that use the GNU GPL protect your rights with two steps:  
 //(1) assert copyright on the software, and (2) offer you this License  
 //giving you legal permission to copy, distribute and/or modify it.  
 //  
 //  For the developers' and authors' protection, the GPL clearly explains  
 //that there is no warranty for this free software.  For both users' and  
 //authors' sake, the GPL requires that modified versions be marked as  
 //changed, so that their problems will not be attributed erroneously to  
 //authors of previous versions.  
 //  
 //  Some devices are designed to deny users access to install or run  
 //modified versions of the software inside them, although the manufacturer  
 //can do so.  This is fundamentally incompatible with the aim of  
 //protecting users' freedom to change the software.  The systematic  
 //pattern of such abuse occurs in the area of products for individuals to  
 //use, which is precisely where it is most unacceptable.  Therefore, we  
 //have designed this version of the GPL to prohibit the practice for those  
 //products.  If such problems arise substantially in other domains, we  
 //stand ready to extend this provision to those domains in future versions  
 //of the GPL, as needed to protect the freedom of users.  
 //  
 //  Finally, every program is threatened constantly by software patents.  
 //States should not allow patents to restrict development and use of  
 //software on general-purpose computers, but in those that do, we wish to  
 //avoid the special danger that patents applied to a free program could  
 //make it effectively proprietary.  To prevent this, the GPL assures that  
 //patents cannot be used to render the program non-free.  
 //  
 //  The precise terms and conditions for copying, distribution and  
 //modification follow.  
 //  
 //                       TERMS AND CONDITIONS  
 //  
 //  0. Definitions.  
 //  
 //  "This License" refers to version 3 of the GNU General Public License.  
 //  
 //  "Copyright" also means copyright-like laws that apply to other kinds of  
 //works, such as semiconductor masks.  
 //  
 //  "The Program" refers to any copyrightable work licensed under this  
 //License.  Each licensee is addressed as "you".  "Licensees" and  
 //"recipients" may be individuals or organizations.  
 //  
 //  To "modify" a work means to copy from or adapt all or part of the work  
 //in a fashion requiring copyright permission, other than the making of an  
 //exact copy.  The resulting work is called a "modified version" of the  
 //earlier work or a work "based on" the earlier work.  
 //  
 //  A "covered work" means either the unmodified Program or a work based  
 //on the Program.  
 //  
 //  To "propagate" a work means to do anything with it that, without  
 //permission, would make you directly or secondarily liable for  
 //infringement under applicable copyright law, except executing it on a  
 //computer or modifying a private copy.  Propagation includes copying,  
 //distribution (with or without modification), making available to the  
 //public, and in some countries other activities as well.  
 //  
 //  To "convey" a work means any kind of propagation that enables other  
 //parties to make or receive copies.  Mere interaction with a user through  
 //a computer network, with no transfer of a copy, is not conveying.  
 //  
 //  An interactive user interface displays "Appropriate Legal Notices"  
 //to the extent that it includes a convenient and prominently visible  
 //feature that (1) displays an appropriate copyright notice, and (2)  
 //tells the user that there is no warranty for the work (except to the  
 //extent that warranties are provided), that licensees may convey the  
 //work under this License, and how to view a copy of this License.  If  
 //the interface presents a list of user commands or options, such as a  
 //menu, a prominent item in the list meets this criterion.  
 //  
 //  1. Source Code.  
 //  
 //  The "source code" for a work means the preferred form of the work  
 //for making modifications to it.  "Object code" means any non-source  
 //form of a work.  
 //  
 //  A "Standard Interface" means an interface that either is an official  
 //standard defined by a recognized standards body, or, in the case of  
 //interfaces specified for a particular programming language, one that  
 //is widely used among developers working in that language.  
 //  
 //  The "System Libraries" of an executable work include anything, other  
 //than the work as a whole, that (a) is included in the normal form of  
 //packaging a Major Component, but which is not part of that Major  
 //Component, and (b) serves only to enable use of the work with that  
 //Major Component, or to implement a Standard Interface for which an  
 //implementation is available to the public in source code form.  A  
 //"Major Component", in this context, means a major essential component  
 //(kernel, window system, and so on) of the specific operating system  
 //(if any) on which the executable work runs, or a compiler used to  
 //produce the work, or an object code interpreter used to run it.  
 //  
 //  The "Corresponding Source" for a work in object code form means all  
 //the source code needed to generate, install, and (for an executable  
 //work) run the object code and to modify the work, including scripts to  
 //control those activities.  However, it does not include the work's  
 //System Libraries, or general-purpose tools or generally available free  
 //programs which are used unmodified in performing those activities but  
 //which are not part of the work.  For example, Corresponding Source  
 //includes interface definition files associated with source files for  
 //the work, and the source code for shared libraries and dynamically  
 //linked subprograms that the work is specifically designed to require,  
 //such as by intimate data communication or control flow between those  
 //subprograms and other parts of the work.  
 //  
 //  The Corresponding Source need not include anything that users  
 //can regenerate automatically from other parts of the Corresponding  
 //Source.  
 //  
 //  The Corresponding Source for a work in source code form is that  
 //same work.  
 //  
 //  2. Basic Permissions.  
 //  
 //  All rights granted under this License are granted for the term of  
 //copyright on the Program, and are irrevocable provided the stated  
 //conditions are met.  This License explicitly affirms your unlimited  
 //permission to run the unmodified Program.  The output from running a  
 //covered work is covered by this License only if the output, given its  
 //content, constitutes a covered work.  This License acknowledges your  
 //rights of fair use or other equivalent, as provided by copyright law.  
 //  
 //  You may make, run and propagate covered works that you do not  
 //convey, without conditions so long as your license otherwise remains  
 //in force.  You may convey covered works to others for the sole purpose  
 //of having them make modifications exclusively for you, or provide you  
 //with facilities for running those works, provided that you comply with  
 //the terms of this License in conveying all material for which you do  
 //not control copyright.  Those thus making or running the covered works  
 //for you must do so exclusively on your behalf, under your direction  
 //and control, on terms that prohibit them from making any copies of  
 //your copyrighted material outside their relationship with you.  
 //  
 //  Conveying under any other circumstances is permitted solely under  
 //the conditions stated below.  Sublicensing is not allowed; section 10  
 //makes it unnecessary.  
 //  
 //  3. Protecting Users' Legal Rights From Anti-Circumvention Law.  
 //  
 //  No covered work shall be deemed part of an effective technological  
 //measure under any applicable law fulfilling obligations under article  
 //11 of the WIPO copyright treaty adopted on 20 December 1996, or  
 //similar laws prohibiting or restricting circumvention of such  
 //measures.  
 //  
 //  When you convey a covered work, you waive any legal power to forbid  
 //circumvention of technological measures to the extent such circumvention  
 //is effected by exercising rights under this License with respect to  
 //the covered work, and you disclaim any intention to limit operation or  
 //modification of the work as a means of enforcing, against the work's  
 //users, your or third parties' legal rights to forbid circumvention of  
 //technological measures.  
 //  
 //  4. Conveying Verbatim Copies.  
 //  
 //  You may convey verbatim copies of the Program's source code as you  
 //receive it, in any medium, provided that you conspicuously and  
 //appropriately publish on each copy an appropriate copyright notice;  
 //keep intact all notices stating that this License and any  
 //non-permissive terms added in accord with section 7 apply to the code;  
 //keep intact all notices of the absence of any warranty; and give all  
 //recipients a copy of this License along with the Program.  
 //  
 //  You may charge any price or no price for each copy that you convey,  
 //and you may offer support or warranty protection for a fee.  
 //  
 //  5. Conveying Modified Source Versions.  
 //  
 //  You may convey a work based on the Program, or the modifications to  
 //produce it from the Program, in the form of source code under the  
 //terms of section 4, provided that you also meet all of these conditions:  
 //  
 //    a) The work must carry prominent notices stating that you modified  
 //    it, and giving a relevant date.  
 //  
 //    b) The work must carry prominent notices stating that it is  
 //    released under this License and any conditions added under section  
 //    7.  This requirement modifies the requirement in section 4 to  
 //    "keep intact all notices".  
 //  
 //    c) You must license the entire work, as a whole, under this  
 //    License to anyone who comes into possession of a copy.  This  
 //    License will therefore apply, along with any applicable section 7  
 //    additional terms, to the whole of the work, and all its parts,  
 //    regardless of how they are packaged.  This License gives no  
 //    permission to license the work in any other way, but it does not  
 //    invalidate such permission if you have separately received it.  
 //  
 //    d) If the work has interactive user interfaces, each must display  
 //    Appropriate Legal Notices; however, if the Program has interactive  
 //    interfaces that do not display Appropriate Legal Notices, your  
 //    work need not make them do so.  
 //  
 //  A compilation of a covered work with other separate and independent  
 //works, which are not by their nature extensions of the covered work,  
 //and which are not combined with it such as to form a larger program,  
 //in or on a volume of a storage or distribution medium, is called an  
 //"aggregate" if the compilation and its resulting copyright are not  
 //used to limit the access or legal rights of the compilation's users  
 //beyond what the individual works permit.  Inclusion of a covered work  
 //in an aggregate does not cause this License to apply to the other  
 //parts of the aggregate.  
 //  
 //  6. Conveying Non-Source Forms.  
 //  
 //  You may convey a covered work in object code form under the terms  
 //of sections 4 and 5, provided that you also convey the  
 //machine-readable Corresponding Source under the terms of this License,  
 //in one of these ways:  
 //  
 //    a) Convey the object code in, or embodied in, a physical product  
 //    (including a physical distribution medium), accompanied by the  
 //    Corresponding Source fixed on a durable physical medium  
 //    customarily used for software interchange.  
 //  
 //    b) Convey the object code in, or embodied in, a physical product  
 //    (including a physical distribution medium), accompanied by a  
 //    written offer, valid for at least three years and valid for as  
 //    long as you offer spare parts or customer support for that product  
 //    model, to give anyone who possesses the object code either (1) a  
 //    copy of the Corresponding Source for all the software in the  
 //    product that is covered by this License, on a durable physical  
 //    medium customarily used for software interchange, for a price no  
 //    more than your reasonable cost of physically performing this  
 //    conveying of source, or (2) access to copy the  
 //    Corresponding Source from a network server at no charge.  
 //  
 //    c) Convey individual copies of the object code with a copy of the  
 //    written offer to provide the Corresponding Source.  This  
 //    alternative is allowed only occasionally and noncommercially, and  
 //    only if you received the object code with such an offer, in accord  
 //    with subsection 6b.  
 //  
 //    d) Convey the object code by offering access from a designated  
 //    place (gratis or for a charge), and offer equivalent access to the  
 //    Corresponding Source in the same way through the same place at no  
 //    further charge.  You need not require recipients to copy the  
 //    Corresponding Source along with the object code.  If the place to  
 //    copy the object code is a network server, the Corresponding Source  
 //    may be on a different server (operated by you or a third party)  
 //    that supports equivalent copying facilities, provided you maintain  
 //    clear directions next to the object code saying where to find the  
 //    Corresponding Source.  Regardless of what server hosts the  
 //    Corresponding Source, you remain obligated to ensure that it is  
 //    available for as long as needed to satisfy these requirements.  
 //  
 //    e) Convey the object code using peer-to-peer transmission, provided  
 //    you inform other peers where the object code and Corresponding  
 //    Source of the work are being offered to the general public at no  
 //    charge under subsection 6d.  
 //  
 //  A separable portion of the object code, whose source code is excluded  
 //from the Corresponding Source as a System Library, need not be  
 //included in conveying the object code work.  
 //  
 //  A "User Product" is either (1) a "consumer product", which means any  
 //tangible personal property which is normally used for personal, family,  
 //or household purposes, or (2) anything designed or sold for incorporation  
 //into a dwelling.  In determining whether a product is a consumer product,  
 //doubtful cases shall be resolved in favor of coverage.  For a particular  
 //product received by a particular user, "normally used" refers to a  
 //typical or common use of that class of product, regardless of the status  
 //of the particular user or of the way in which the particular user  
 //actually uses, or expects or is expected to use, the product.  A product  
 //is a consumer product regardless of whether the product has substantial  
 //commercial, industrial or non-consumer uses, unless such uses represent  
 //the only significant mode of use of the product.  
 //  
 //  "Installation Information" for a User Product means any methods,  
 //procedures, authorization keys, or other information required to install  
 //and execute modified versions of a covered work in that User Product from  
 //a modified version of its Corresponding Source.  The information must  
 //suffice to ensure that the continued functioning of the modified object  
 //code is in no case prevented or interfered with solely because  
 //modification has been made.  
 //  
 //  If you convey an object code work under this section in, or with, or  
 //specifically for use in, a User Product, and the conveying occurs as  
 //part of a transaction in which the right of possession and use of the  
 //User Product is transferred to the recipient in perpetuity or for a  
 //fixed term (regardless of how the transaction is characterized), the  
 //Corresponding Source conveyed under this section must be accompanied  
 //by the Installation Information.  But this requirement does not apply  
 //if neither you nor any third party retains the ability to install  
 //modified object code on the User Product (for example, the work has  
 //been installed in ROM).  
 //  
 //  The requirement to provide Installation Information does not include a  
 //requirement to continue to provide support service, warranty, or updates  
 //for a work that has been modified or installed by the recipient, or for  
 //the User Product in which it has been modified or installed.  Access to a  
 //network may be denied when the modification itself materially and  
 //adversely affects the operation of the network or violates the rules and  
 //protocols for communication across the network.  
 //  
 //  Corresponding Source conveyed, and Installation Information provided,  
 //in accord with this section must be in a format that is publicly  
 //documented (and with an implementation available to the public in  
 //source code form), and must require no special password or key for  
 //unpacking, reading or copying.  
 //  
 //  7. Additional Terms.  
 //  
 //  "Additional permissions" are terms that supplement the terms of this  
 //License by making exceptions from one or more of its conditions.  
 //Additional permissions that are applicable to the entire Program shall  
 //be treated as though they were included in this License, to the extent  
 //that they are valid under applicable law.  If additional permissions  
 //apply only to part of the Program, that part may be used separately  
 //under those permissions, but the entire Program remains governed by  
 //this License without regard to the additional permissions.  
 //  
 //  When you convey a copy of a covered work, you may at your option  
 //remove any additional permissions from that copy, or from any part of  
 //it.  (Additional permissions may be written to require their own  
 //removal in certain cases when you modify the work.)  You may place  
 //additional permissions on material, added by you to a covered work,  
 //for which you have or can give appropriate copyright permission.  
 //  
 //  Notwithstanding any other provision of this License, for material you  
 //add to a covered work, you may (if authorized by the copyright holders of  
 //that material) supplement the terms of this License with terms:  
 //  
 //    a) Disclaiming warranty or limiting liability differently from the  
 //    terms of sections 15 and 16 of this License; or  
 //  
 //    b) Requiring preservation of specified reasonable legal notices or  
 //    author attributions in that material or in the Appropriate Legal  
 //    Notices displayed by works containing it; or  
 //  
 //    c) Prohibiting misrepresentation of the origin of that material, or  
 //    requiring that modified versions of such material be marked in  
 //    reasonable ways as different from the original version; or  
 //  
 //    d) Limiting the use for publicity purposes of names of licensors or  
 //    authors of the material; or  
 //  
 //    e) Declining to grant rights under trademark law for use of some  
 //    trade names, trademarks, or service marks; or  
 //  
 //    f) Requiring indemnification of licensors and authors of that  
 //    material by anyone who conveys the material (or modified versions of  
 //    it) with contractual assumptions of liability to the recipient, for  
 //    any liability that these contractual assumptions directly impose on  
 //    those licensors and authors.  
 //  
 //  All other non-permissive additional terms are considered "further  
 //restrictions" within the meaning of section 10.  If the Program as you  
 //received it, or any part of it, contains a notice stating that it is  
 //governed by this License along with a term that is a further  
 //restriction, you may remove that term.  If a license document contains  
 //a further restriction but permits relicensing or conveying under this  
 //License, you may add to a covered work material governed by the terms  
 //of that license document, provided that the further restriction does  
 //not survive such relicensing or conveying.  
 //  
 //  If you add terms to a covered work in accord with this section, you  
 //must place, in the relevant source files, a statement of the  
 //additional terms that apply to those files, or a notice indicating  
 //where to find the applicable terms.  
 //  
 //  Additional terms, permissive or non-permissive, may be stated in the  
 //form of a separately written license, or stated as exceptions;  
 //the above requirements apply either way.  
 //  
 //  8. Termination.  
 //  
 //  You may not propagate or modify a covered work except as expressly  
 //provided under this License.  Any attempt otherwise to propagate or  
 //modify it is void, and will automatically terminate your rights under  
 //this License (including any patent licenses granted under the third  
 //paragraph of section 11).  
 //  
 //  However, if you cease all violation of this License, then your  
 //license from a particular copyright holder is reinstated (a)  
 //provisionally, unless and until the copyright holder explicitly and  
 //finally terminates your license, and (b) permanently, if the copyright  
 //holder fails to notify you of the violation by some reasonable means  
 //prior to 60 days after the cessation.  
 //  
 //  Moreover, your license from a particular copyright holder is  
 //reinstated permanently if the copyright holder notifies you of the  
 //violation by some reasonable means, this is the first time you have  
 //received notice of violation of this License (for any work) from that  
 //copyright holder, and you cure the violation prior to 30 days after  
 //your receipt of the notice.  
 //  
 //  Termination of your rights under this section does not terminate the  
 //licenses of parties who have received copies or rights from you under  
 //this License.  If your rights have been terminated and not permanently  
 //reinstated, you do not qualify to receive new licenses for the same  
 //material under section 10.  
 //  
 //  9. Acceptance Not Required for Having Copies.  
 //  
 //  You are not required to accept this License in order to receive or  
 //run a copy of the Program.  Ancillary propagation of a covered work  
 //occurring solely as a consequence of using peer-to-peer transmission  
 //to receive a copy likewise does not require acceptance.  However,  
 //nothing other than this License grants you permission to propagate or  
 //modify any covered work.  These actions infringe copyright if you do  
 //not accept this License.  Therefore, by modifying or propagating a  
 //covered work, you indicate your acceptance of this License to do so.  
 //  
 //  10. Automatic Licensing of Downstream Recipients.  
 //  
 //  Each time you convey a covered work, the recipient automatically  
 //receives a license from the original licensors, to run, modify and  
 //propagate that work, subject to this License.  You are not responsible  
 //for enforcing compliance by third parties with this License.  
 //  
 //  An "entity transaction" is a transaction transferring control of an  
 //organization, or substantially all assets of one, or subdividing an  
 //organization, or merging organizations.  If propagation of a covered  
 //work results from an entity transaction, each party to that  
 //transaction who receives a copy of the work also receives whatever  
 //licenses to the work the party's predecessor in interest had or could  
 //give under the previous paragraph, plus a right to possession of the  
 //Corresponding Source of the work from the predecessor in interest, if  
 //the predecessor has it or can get it with reasonable efforts.  
 //  
 //  You may not impose any further restrictions on the exercise of the  
 //rights granted or affirmed under this License.  For example, you may  
 //not impose a license fee, royalty, or other charge for exercise of  
 //rights granted under this License, and you may not initiate litigation  
 //(including a cross-claim or counterclaim in a lawsuit) alleging that  
 //any patent claim is infringed by making, using, selling, offering for  
 //sale, or importing the Program or any portion of it.  
 //  
 //  11. Patents.  
 //  
 //  A "contributor" is a copyright holder who authorizes use under this  
 //License of the Program or a work on which the Program is based.  The  
 //work thus licensed is called the contributor's "contributor version".  
 //  
 //  A contributor's "essential patent claims" are all patent claims  
 //owned or controlled by the contributor, whether already acquired or  
 //hereafter acquired, that would be infringed by some manner, permitted  
 //by this License, of making, using, or selling its contributor version,  
 //but do not include claims that would be infringed only as a  
 //consequence of further modification of the contributor version.  For  
 //purposes of this definition, "control" includes the right to grant  
 //patent sublicenses in a manner consistent with the requirements of  
 //this License.  
 //  
 //  Each contributor grants you a non-exclusive, worldwide, royalty-free  
 //patent license under the contributor's essential patent claims, to  
 //make, use, sell, offer for sale, import and otherwise run, modify and  
 //propagate the contents of its contributor version.  
 //  
 //  In the following three paragraphs, a "patent license" is any express  
 //agreement or commitment, however denominated, not to enforce a patent  
 //(such as an express permission to practice a patent or covenant not to  
 //sue for patent infringement).  To "grant" such a patent license to a  
 //party means to make such an agreement or commitment not to enforce a  
 //patent against the party.  
 //  
 //  If you convey a covered work, knowingly relying on a patent license,  
 //and the Corresponding Source of the work is not available for anyone  
 //to copy, free of charge and under the terms of this License, through a  
 //publicly available network server or other readily accessible means,  
 //then you must either (1) cause the Corresponding Source to be so  
 //available, or (2) arrange to deprive yourself of the benefit of the  
 //patent license for this particular work, or (3) arrange, in a manner  
 //consistent with the requirements of this License, to extend the patent  
 //license to downstream recipients.  "Knowingly relying" means you have  
 //actual knowledge that, but for the patent license, your conveying the  
 //covered work in a country, or your recipient's use of the covered work  
 //in a country, would infringe one or more identifiable patents in that  
 //country that you have reason to believe are valid.  
 //  
 //  If, pursuant to or in connection with a single transaction or  
 //arrangement, you convey, or propagate by procuring conveyance of, a  
 //covered work, and grant a patent license to some of the parties  
 //receiving the covered work authorizing them to use, propagate, modify  
 //or convey a specific copy of the covered work, then the patent license  
 //you grant is automatically extended to all recipients of the covered  
 //work and works based on it.  
 //  
 //  A patent license is "discriminatory" if it does not include within  
 //the scope of its coverage, prohibits the exercise of, or is  
 //conditioned on the non-exercise of one or more of the rights that are  
 //specifically granted under this License.  You may not convey a covered  
 //work if you are a party to an arrangement with a third party that is  
 //in the business of distributing software, under which you make payment  
 //to the third party based on the extent of your activity of conveying  
 //the work, and under which the third party grants, to any of the  
 //parties who would receive the covered work from you, a discriminatory  
 //patent license (a) in connection with copies of the covered work  
 //conveyed by you (or copies made from those copies), or (b) primarily  
 //for and in connection with specific products or compilations that  
 //contain the covered work, unless you entered into that arrangement,  
 //or that patent license was granted, prior to 28 March 2007.  
 //  
 //  Nothing in this License shall be construed as excluding or limiting  
 //any implied license or other defenses to infringement that may  
 //otherwise be available to you under applicable patent law.  
 //  
 //  12. No Surrender of Others' Freedom.  
 //  
 //  If conditions are imposed on you (whether by court order, agreement or  
 //otherwise) that contradict the conditions of this License, they do not  
 //excuse you from the conditions of this License.  If you cannot convey a  
 //covered work so as to satisfy simultaneously your obligations under this  
 //License and any other pertinent obligations, then as a consequence you may  
 //not convey it at all.  For example, if you agree to terms that obligate you  
 //to collect a royalty for further conveying from those to whom you convey  
 //the Program, the only way you could satisfy both those terms and this  
 //License would be to refrain entirely from conveying the Program.  
 //  
 //  13. Use with the GNU Affero General Public License.  
 //  
 //  Notwithstanding any other provision of this License, you have  
 //permission to link or combine any covered work with a work licensed  
 //under version 3 of the GNU Affero General Public License into a single  
 //combined work, and to convey the resulting work.  The terms of this  
 //License will continue to apply to the part which is the covered work,  
 //but the special requirements of the GNU Affero General Public License,  
 //section 13, concerning interaction through a network will apply to the  
 //combination as such.  
 //  
 //  14. Revised Versions of this License.  
 //  
 //  The Free Software Foundation may publish revised and/or new versions of  
 //the GNU General Public License from time to time.  Such new versions will  
 //be similar in spirit to the present version, but may differ in detail to  
 //address new problems or concerns.  
 //  
 //  Each version is given a distinguishing version number.  If the  
 //Program specifies that a certain numbered version of the GNU General  
 //Public License "or any later version" applies to it, you have the  
 //option of following the terms and conditions either of that numbered  
 //version or of any later version published by the Free Software  
 //Foundation.  If the Program does not specify a version number of the  
 //GNU General Public License, you may choose any version ever published  
 //by the Free Software Foundation.  
 //  
 //  If the Program specifies that a proxy can decide which future  
 //versions of the GNU General Public License can be used, that proxy's  
 //public statement of acceptance of a version permanently authorizes you  
 //to choose that version for the Program.  
 //  
 //  Later license versions may give you additional or different  
 //permissions.  However, no additional obligations are imposed on any  
 //author or copyright holder as a result of your choosing to follow a  
 //later version.  
 //  
 //  15. Disclaimer of Warranty.  
 //  
 //  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY  
 //APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT  
 //HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY  
 //OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,  
 //THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  
 //PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM  
 //IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF  
 //ALL NECESSARY SERVICING, REPAIR OR CORRECTION.  
 //  
 //  16. Limitation of Liability.  
 //  
 //  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING  
 //WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS  
 //THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY  
 //GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE  
 //USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF  
 //DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD  
 //PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),  
 //EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF  
 //SUCH DAMAGES.  
 //  
 //  17. Interpretation of Sections 15 and 16.  
 //  
 //  If the disclaimer of warranty and limitation of liability provided  
 //above cannot be given local legal effect according to their terms,  
 //reviewing courts shall apply local law that most closely approximates  
 //an absolute waiver of all civil liability in connection with the  
 //Program, unless a warranty or assumption of liability accompanies a  
 //copy of the Program in return for a fee.  
 //  
 //                     END OF TERMS AND CONDITIONS  
 //  
 //            How to Apply These Terms to Your New Programs  
 //  
 //  If you develop a new program, and you want it to be of the greatest  
 //possible use to the public, the best way to achieve this is to make it  
 //free software which everyone can redistribute and change under these terms.  
 //  
 //  To do so, attach the following notices to the program.  It is safest  
 //to attach them to the start of each source file to most effectively  
 //state the exclusion of warranty; and each file should have at least  
 //the "copyright" line and a pointer to where the full notice is found.  
 //  
 //    <one line to give the program's name and a brief idea of what it does.>  
 //    Copyright (C) <year>  <name of author>  
 //  
 //    This program is free software: you can redistribute it and/or modify  
 //    it under the terms of the GNU General Public License as published by  
 //    the Free Software Foundation, either version 3 of the License, or  
 //    (at your option) any later version.  
 //  
 //    This program is distributed in the hope that it will be useful,  
 //    but WITHOUT ANY WARRANTY; without even the implied warranty of  
 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
 //    GNU General Public License for more details.  
 //  
 //    You should have received a copy of the GNU General Public License  
 //    along with this program.  If not, see <http://www.gnu.org/licenses/>.  
 //  
 //Also add information on how to contact you by electronic and paper mail.  
 //  
 //  If the program does terminal interaction, make it output a short  
 //notice like this when it starts in an interactive mode:  
 //  
 //    <program>  Copyright (C) <year>  <name of author>  
 //    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.  
 //    This is free software, and you are welcome to redistribute it  
 //    under certain conditions; type `show c' for details.  
 //  
 //The hypothetical commands `show w' and `show c' should show the appropriate  
 //parts of the General Public License.  Of course, your program's commands  
 //might be different; for a GUI interface, you would use an "about box".  
 //  
 //  You should also get your employer (if you work as a programmer) or school,  
 //if any, to sign a "copyright disclaimer" for the program, if necessary.  
 //For more information on this, and how to apply and follow the GNU GPL, see  
 //<http://www.gnu.org/licenses/>.  
 //  
 //  The GNU General Public License does not permit incorporating your program  
 //into proprietary programs.  If your program is a subroutine library, you  
 //may consider it more useful to permit linking proprietary applications with  
 //the library.  If this is what you want to do, use the GNU Lesser General  
 //Public License instead of this License.  But first, please read  
 //<http://www.gnu.org/philosophy/why-not-lgpl.html>.  
 //-------------------------------------------------------------------------------------------------  
 //--------------------------------------------------------------------------------  
 #define MODULE_GMP_RATS  
   
 #include <assert.h>  
 #include <stdio.h>  
 #include <string.h>  
   
 #include "bstrfunc.h"  
 #include "charfunc.h"  
 #include "gmp_ints.h"  
 #include "gmp_rats.h"  
   
 #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)  
    #include "ccmalloc.h"  
 #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)  
    #include "tclalloc.h"  
 #else  
    #include <malloc.h>  
 #endif  
   
   
 /******************************************************************/  
 /***  STATUS FUNCTIONS  *******************************************/  
 /******************************************************************/  
 //Functions in this category provide information about rational  
 //numbers.  
 //08/08/01:  Visual inspection OK.  
 int GMP_RATS_mpq_is_nan(const GMP_RATS_mpq_struct *rn)  
    {  
    assert(rn != NULL);  
   
    //A rational number is NAN in one of two  
    //circumstances.  If either of the integer components  
    //is NAN, or else if there is a zero denominator.  
    if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))  
       {  
       return(1);  
       }  
    if (GMP_INTS_mpz_is_zero(&(rn->den)))  
       {  
       return(1);  
       }  
   
    //We're clean ...  
    return(0);  
    }  
   
   
 /******************************************************************/  
 /***  INITIALIZATION, CLEARING, AND SETTING FUNCTIONS  ************/  
 /******************************************************************/  
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_init(GMP_RATS_mpq_struct *arg)  
    {  
    //Eyeball the input parameter.  
    assert(arg != NULL);  
   
    //Initialize the numerator and denominator.  
    GMP_INTS_mpz_init(&(arg->num));  
    GMP_INTS_mpz_init(&(arg->den));  
   
    //Canonically, we must start off as 0/1--canonical zero.  
    GMP_INTS_mpz_set_ui(&(arg->num), 0);  
    GMP_INTS_mpz_set_ui(&(arg->den), 1);  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_clear(GMP_RATS_mpq_struct *arg)  
    {  
    //Eyeball the input parameter.  
    assert(arg != NULL);  
   
    //Clear the numerator and denominator.  The called functions  
    //will check for NULL pointers and so forth.  
    GMP_INTS_mpz_clear(&(arg->num));  
    GMP_INTS_mpz_clear(&(arg->den));  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_set_si(GMP_RATS_mpq_struct *arg,  
                          int num,  
                          int den)  
    {  
    //Eyeball the input parameters.  
    assert(arg != NULL);  
   
    //Set the numerator and denominator.  
    GMP_INTS_mpz_set_si(&(arg->num), num);  
    GMP_INTS_mpz_set_si(&(arg->den), den);  
    }  
   
   
 //08/08/01:  Visual inspection OK.  
 void GMP_RATS_mpq_copy(      GMP_RATS_mpq_struct *dst,  
                        const GMP_RATS_mpq_struct *src)  
    {  
    assert(dst != NULL);  
    assert(src != NULL);  
   
    GMP_INTS_mpz_copy(&(dst->num), &(src->num));  
    GMP_INTS_mpz_copy(&(dst->den), &(src->den));  
    }  
   
   
 //08/13/01:  Visual inspection OK.  
 void GMP_RATS_mpq_swap( GMP_RATS_mpq_struct *a,  
                         GMP_RATS_mpq_struct *b)  
    {  
    assert(a != NULL);  
    assert(b != NULL);  
   
    //Handle the swap by swapping integer components.  
    GMP_INTS_mpz_swap(&(a->num), &(b->num));  
    GMP_INTS_mpz_swap(&(a->den), &(b->den));  
    }  
   
   
 //08/13/01:  Visual inspection OK.  
 void GMP_RATS_mpq_swap_components(GMP_RATS_mpq_struct *arg)  
    {  
    assert(arg != NULL);  
   
    GMP_INTS_mpz_swap(&(arg->num), &(arg->den));  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_set_complex_slash_sepd_rat_num(const char *s,  
                                                  int *failure,  
                                                  GMP_RATS_mpq_struct *rn)  
    {  
    char *slash_posn, *numerator, *denominator;  
    int s_len, numerator_len, denominator_len;  
    int i;  
   
    //Eyeball the input parameters.  
    assert(s != NULL);  
    assert(failure != NULL);  
    assert(rn != NULL);  
   
    //Start off believing there is no failure.  
    *failure = 0;  
   
    //Figure out if there is one and only one slash in the  
    //string.  If this condition isn't met, we cannot  
    //go further.  
    slash_posn = strchr(s, '/');  
    if (!slash_posn)  
       {  
       *failure = 1;  
       return;  
       }  
    if (strchr(slash_posn + 1, '/')) //There is a second occurence.  
       {  
       *failure = 1;  
       return;  
       }  
   
    //At this point we have one and only one slash.  
    //Crack the string in two.  We must do this because the  
    //input is a constant string.  We are not allowed to touch it  
    //in the logical domain because of the "const" keyword.  We can't  
    //do this in the physical domain because the debugger will nail  
    //us for it.  
    s_len = strlen(s);  
    numerator_len = slash_posn - s;  
    denominator_len = strlen(slash_posn + 1);  
    #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)  
       numerator   = CCMALLOC_malloc(sizeof(char) * (numerator_len   + 1));  
       denominator = CCMALLOC_malloc(sizeof(char) * (denominator_len + 1));  
    #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)  
       numerator   = TclpAlloc(sizeof(char) * (numerator_len   + 1));  
       denominator = TclpAlloc(sizeof(char) * (denominator_len + 1));  
    #else  
       numerator   = malloc(sizeof(char) * (numerator_len   + 1));  
       denominator = malloc(sizeof(char) * (denominator_len + 1));  
    #endif  
   
    assert(numerator   != NULL);  
    assert(denominator != NULL);  
   
    for (i=0; i<numerator_len; i++)  
       {  
       numerator[i] = s[i];  
       }    
    numerator[numerator_len] = 0;  
     
    for (i=0; i<denominator_len; i++)  
       {  
       denominator[i] = s[slash_posn - s + 1 + i];  
       }  
    denominator[denominator_len] = 0;  
   
    //Try to parse out the numerator as an arbitrary integer.  
    //If this can't be done, it is an immediate failure.  
    GMP_INTS_mpz_set_general_int(&(rn->num),  
                                 failure,  
                                 numerator);  
    if (*failure)  
       {  
       *failure = 1;  //Clamp to 1, don't know what non-zero value  
                      //was there.  
       goto ret_pt;  
       }  
   
    //Try to parse out the denominator.  
    GMP_INTS_mpz_set_general_int(&(rn->den),  
                                 failure,  
                                 denominator);  
    if (*failure)  
       {  
       *failure = 1;  //Clamp to 1, don't know what non-zero value  
                      //was there.  
       goto ret_pt;  
       }  
   
    //At this point, we have both a numerator and denominator.  
    //Clean up and return.  
    ret_pt:  
    #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)  
       CCMALLOC_free(numerator);  
       CCMALLOC_free(denominator);  
    #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)  
       TclpFree(numerator);  
       TclpFree(denominator);  
    #else  
       free(numerator);  
       free(denominator);  
    #endif  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_set_sci_not_rat_num(const char *s,  
                                       int *failure,  
                                       GMP_RATS_mpq_struct *rn)  
    {  
    int parse_failure;  
       //Return code from the floating point parsing  
       //function.  
    char mant_sign;  
       //Sign character, if any, from the mantissa,  
       //or N otherwise.  
    size_t mant_bdp;  
       //The index to the start of the mantissa before  
       //the decimal point.  
    size_t mant_bdp_len;  
       //The length of the mantissa before the decimal  
       //point.  Zero means not defined, i.e. that  
       //no characters were parsed and interpreted as  
       //that part of a floating point number.  
    size_t mant_adp;  
    size_t mant_adp_len;  
       //Similar fields for after the decimal point.  
    char exp_sign;  
       //Sign of the exponent, if any, or N otherwise.  
    size_t exp;  
    size_t exp_len;  
       //Similar fields as to the mantissa, but for the  
       //exponent.  
    size_t si;  
       //Iteration variable.  
    int exponent_val;  
       //The value of the exponent.  We can't accept  
       //an exponent outside the range of a 24-bit  
       //signed integer.  The 24-bit limit is arbitrary.  
       //For one thing, it gives room to detect overflow  
       //as are adding and multiplying by 10.  
   
    //Eyeball the input parameters.  
    assert(s != NULL);  
    assert(failure != NULL);  
    assert(rn != NULL);  
       //Subcomponents of the rational number will be checked as  
       //we make integer calls, if we're in debug mode.  
   
    //Start off believing no failure.  
    *failure = 0;  
   
    //Set the output to 0/1.  This is the default case for some  
    //steps below.  
    GMP_RATS_mpq_set_si(rn, 0, 1);  
   
    //Attempt to parse the number as a general number  
    //in scientific notation.  
    BSTRFUNC_parse_gen_sci_not_num(s,  
                                   &parse_failure,  
                                   &mant_sign,  
                                   &mant_bdp,  
                                   &mant_bdp_len,  
                                   &mant_adp,  
                                   &mant_adp_len,  
                                   &exp_sign,  
                                   &exp,  
                                   &exp_len);  
   
    //If it wouldn't parse as a general number, can't go further.  
    if (parse_failure)  
       {  
       *failure = 1;  
       return;  
       }  
    else  
       {  
       //The number parsed out.  The general strategy is to form a rational number  
       //consisting of the mantissa, with the decimal point shifted fully right, over  
       //a denominator of 1.  From there, we process the exponent and combine it with  
       //the number of characters after the decimal point to form a virtual exponent.  
       //If the exponent is positive, we multiply the numerator by the power of 10.  
       //If the exponent is negative, we multiply the denominator by that power of 10.  
   
       //We want to trim the trailing zeros off of the portion of the mantissa after the  
       //decimal point.  We only need to back up indices, no need to make copies, etc.  
       //Note that it is possible that there are only zeros, in which case we'll end  
       //up with a length of zero.  
       while ((mant_adp_len > 0) && (s[mant_adp + mant_adp_len - 1]=='0'))  
          mant_adp_len--;  
   
       //Trim the leading zeros off of the portion of the mantissa before the  
       //decimal point.  Note that it is possible that there is only a zero,  
       //so we may trim it down to nothing.  
       while ((mant_bdp_len > 0) && (s[mant_bdp]=='0'))  
          {  
          mant_bdp++;  
          mant_bdp_len--;  
          }  
   
       //If we have only zeros in the mantissa, both before the  
       //decimal point and after, then we return 0.  
       if ((mant_bdp_len + mant_adp_len) == 0)  
          {  
          *failure = 0;  
          return;  
          }  
         
       //Convert the numerator to an integer which represents the  
       //part before the mantissa and the part after the mantissa  
       //concatenated as an integer.  We could call a function to do  
       //this, but the function is not really any better in algorithm.  
       //We can do it ourselves.  
       GMP_INTS_mpz_set_ui(&(rn->num), 0);  
       for (si = 0; si < mant_bdp_len; si++)  
          {  
          int val;  
   
          GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);  
          val = CHARFUNC_digit_to_val(s[mant_bdp + si]);  
          if (val >= 0)  
             GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);  
          }  
       for (si = 0; si < mant_adp_len; si++)  
          {  
          int val;  
   
          GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);  
          val = CHARFUNC_digit_to_val(s[mant_adp + si]);  
          if (val >= 0)  
             GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);  
          }  
   
       //The numerator should now have an integer which is  
       //The absolute value of the mantissa.  Process the possible  
       //sign.  
       if (mant_sign == '-')  
          GMP_INTS_mpz_negate(&(rn->num));  
   
       //We now need to form a value from the exponent, if any.  
       //First, tackle the exponent.  Process the  
       //exponent into a signed integer.  We have to  
       //balk at anything outside of 24 bits.  The  
       //procedure used automatically handles  
       //leading zeros correctly.  
       exponent_val = 0;  
       for (si=exp; si<(exp+exp_len); si++)  
          {  
          int val;  
   
          val = CHARFUNC_digit_to_val(s[si]);  
   
          assert(val >= 0 && val <= 9);  
   
          exponent_val *= 10;  
          exponent_val += val;  
   
          if (((exp_sign=='-') && (exponent_val>8388608))  
             ||  
             ((exp_sign != '-') && (exponent_val>8388607)))  
             {  
             *failure = 1;  
             return;  
             }  
          }  
   
       //If we're here, the exponent has been computed and  
       //is within 24 bits.  However, we need to adjust for  
       //the sign.  
       if (exp_sign == '-')  
          exponent_val = -exponent_val;  
   
       //We need to adjust the exponent for the number of digits  
       //after the decimal point.  
       exponent_val -= mant_adp_len;    
         
       //Again, clip for size.  
       if ((exponent_val < -8388608) || (exponent_val > 8388607))  
          {  
          *failure = 1;  
          return;  
          }  
           
       //There are two cases to consider.  If the exponent  
       //is positive, we need to multiply the numerator  
       //by 10 exponentiated to the power of the exponent.  
       //If the exponent is negative, we need to do the  
       //same thing to the denominator.  If the exponent  
       //is negative, we don't need to do anything.  
       if (exponent_val > 0)  
          {  
          GMP_INTS_mpz_struct k10, k10_exponentiated;  
   
          GMP_INTS_mpz_init(&k10);  
          GMP_INTS_mpz_init(&k10_exponentiated);  
   
          GMP_INTS_mpz_set_ui(&k10, 10);  
   
          GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, exponent_val);  
   
          GMP_INTS_mpz_mul(&(rn->num), &(rn->num), &k10_exponentiated);  
   
          GMP_INTS_mpz_clear(&k10);  
          GMP_INTS_mpz_clear(&k10_exponentiated);  
   
          *failure = 0;  
   
          if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))  
             *failure = 1;  
   
          return;  
          }  
       else if (exponent_val < 0)  
          {  
          GMP_INTS_mpz_struct k10, k10_exponentiated;  
   
          GMP_INTS_mpz_init(&k10);  
          GMP_INTS_mpz_init(&k10_exponentiated);  
   
          GMP_INTS_mpz_set_ui(&k10, 10);  
   
          GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, -exponent_val);  
   
          GMP_INTS_mpz_mul(&(rn->den), &(rn->den), &k10_exponentiated);  
   
          GMP_INTS_mpz_clear(&k10);  
          GMP_INTS_mpz_clear(&k10_exponentiated);  
   
          *failure = 0;  
   
          if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))  
             *failure = 1;  
   
          return;  
          }  
       }  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_set_all_format_rat_num(const char *s,  
                                          int *failure,  
                                          GMP_RATS_mpq_struct *rn)  
    {  
    //Eyeball the input parameters.  
    assert(s != NULL);  
    assert(failure != NULL);  
    assert(rn != NULL);  
   
    //Assume no failure.  
    *failure = 0;  
   
    //Try in order to parse as integers with slash then  
    //as number in scientific notation.  
    GMP_RATS_mpq_set_complex_slash_sepd_rat_num(s,  
                                                failure,  
                                                rn);  
    if (!*failure)  
       return;  
   
    GMP_RATS_mpq_set_sci_not_rat_num(s,  
                                     failure,  
                                     rn);  
   
    if (*failure)  
       *failure = 1;  //Clamp output.  
    }  
   
   
 /******************************************************************/  
 /***  NORMALIZATION FUNCTIONS  ************************************/  
 /******************************************************************/  
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_normalize_sign(GMP_RATS_mpq_struct *rn)  
    {  
    //Eyeball the input.  
    assert(rn != NULL);  
   
    if (GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))  
       {  
       //Both negative, can negate both, this leaves both positive,  
       //which is the normalized form for a positive rational  
       //number.  
       GMP_INTS_mpz_negate(&rn->num);  
       GMP_INTS_mpz_negate(&rn->den);  
       }  
    else if (!GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))  
       {  
       //Denominator neg, numerator non-neg, can negate both.  This  
       //will leave numerator neg, denominator pos, which is  
       //normalized form for negative rational number.  
       GMP_INTS_mpz_negate(&rn->num);  
       GMP_INTS_mpz_negate(&rn->den);  
       }      
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 void GMP_RATS_mpq_normalize(GMP_RATS_mpq_struct *rn)  
    {  
    //Eyeball the input.  
    assert(rn != NULL);  
   
    //Cover some special cases.  If either component has flags  
    //set, don't even touch it.  
    if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))  
       {  
       return;  
       }  
    //If the denominator is zero, normalize it to 1/0, the canonical  
    //for for an illegal rational number.  
    else if (GMP_INTS_mpz_is_zero(&(rn->den)))  
       {  
       GMP_RATS_mpq_set_si(rn, 1, 0);  
       return;  
       }  
    //If the numerator is zero, convert the number to the canonical  
    //form for zero of 0/1.  
    else if (GMP_INTS_mpz_is_zero(&(rn->num)))  
       {  
       GMP_RATS_mpq_set_si(rn, 0, 1);  
       return;  
       }  
    else  
       {  
       int num_is_neg;  
       int den_is_neg;  
       GMP_INTS_mpz_struct gcd, quotient, remainder;  
   
       //Allocate space for the integers used.  
       GMP_INTS_mpz_init(&gcd);  
       GMP_INTS_mpz_init(&quotient);  
       GMP_INTS_mpz_init(&remainder);  
   
       //This is the most normal case, where we need to  
       //look at reducing the numerator and denominator.  
       //One way to do it would be to obtain the g.c.d.  
       //and divide this out, and this is the route  
       //we'll take.  However, must grab out the sign.  
       if (GMP_INTS_mpz_is_neg(&(rn->num)))  
          {  
          num_is_neg = 1;  
          GMP_INTS_mpz_negate(&(rn->num));  
          }  
       else  
          {  
          num_is_neg = 0;  
          }  
   
       if (GMP_INTS_mpz_is_neg(&(rn->den)))  
          {  
          den_is_neg = 1;  
          GMP_INTS_mpz_negate(&(rn->den));  
          }  
       else  
          {  
          den_is_neg = 0;  
          }  
   
       //Calculate the GCD.  
       GMP_INTS_mpz_gcd(&gcd, &(rn->num), &(rn->den));  
   
       //Divide the numerator by the GCD and store it  
       //back.  
       GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,  
                            &(rn->num), &gcd);  
       GMP_INTS_mpz_copy(&(rn->num), &quotient);  
   
       //Divide the denominator by the GCD and store it  
       //back.  
       GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,  
                            &(rn->den), &gcd);  
       GMP_INTS_mpz_copy(&(rn->den), &quotient);  
   
       //We now need to adjust the sign.  Both the  
       //numerator and denominator are definitely  
       //positive.  Need to make the numerator  
       //negative if either but not both of the  
       //original signs were negative.  
       if ((num_is_neg && !den_is_neg) || (!num_is_neg && den_is_neg))  
          {  
          GMP_INTS_mpz_negate(&(rn->num));  
          }  
   
       //Deallocate space for the integers used.  
       GMP_INTS_mpz_clear(&gcd);  
       GMP_INTS_mpz_clear(&quotient);  
       GMP_INTS_mpz_clear(&remainder);  
   
       return;  
       }      
    }  
   
   
 /******************************************************************/  
 /***  ARITHMETIC FUNCTIONS  ***************************************/  
 /******************************************************************/  
 //08/08/01:  Visual inspection OK.  
 void GMP_RATS_mpq_add(      GMP_RATS_mpq_struct *result,  
                       const GMP_RATS_mpq_struct *arg1,  
                       const GMP_RATS_mpq_struct *arg2)  
    {  
    GMP_RATS_mpq_struct rv;  
    GMP_INTS_mpz_struct temp;  
   
    //Eyeball the input parameters.  
    assert(result != NULL);  
    assert(arg1   != NULL);  
    assert(arg2   != NULL);  
   
    //Generally speaking, we do not want to require that  
    //the arguments and the result be distinct, as this is  
    //too much of a restriction on the caller.  The approach  
    //taken, somewhat wasteful, is to allocate a place for  
    //the return value.  
    //  
    //For addition, if we are adding a/b and c/d, the  
    //result is necessarily algebraically  
    //(ad + cb)/bd.  
    //  
    //If either rational number in the input is invalid,  
    //flag the result as invalid.  
    if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))  
       {  
       GMP_RATS_mpq_set_si(result, 1, 0);  
       }  
    else  
       {  
       //Both rational numbers are OK.  Can simply stage the  
       //result by the algebraic identity and then  
       //normalize it.  Only need one temporary variable.  
       //  
       //Initialize the rational number that we will use to  
       //hold return value in case it is the same as one  
       //or both of the arguments.  
       GMP_RATS_mpq_init(&rv);  
   
       //Initialize the temporary integer.  
       GMP_INTS_mpz_init(&temp);  
   
       //numerator = a * d  
       GMP_INTS_mpz_mul(&(rv.num), &(arg1->num), &(arg2->den));  
   
       //temp = c * b  
       GMP_INTS_mpz_mul(&temp, &(arg2->num), &(arg1->den));  
   
       //numerator = a * d + c * b  
       GMP_INTS_mpz_add(&(rv.num), &(rv.num), &temp);  
   
       //denominator = b * d  
       GMP_INTS_mpz_mul(&(rv.den), &(arg1->den), &(arg2->den));  
   
       //Copy the temporary result to the actual return value.  
       //Had to wait until now in case result was the same  
       //as either or both args.  
       GMP_RATS_mpq_copy(result, &rv);  
   
       //Normalize the result.  
       GMP_RATS_mpq_normalize(result);  
   
       //Free dynamic memory.  
       GMP_RATS_mpq_clear(&rv);  
       GMP_INTS_mpz_clear(&temp);  
       }  
    }  
   
   
 //08/08/01:  Visual inspection OK.  
 void GMP_RATS_mpq_sub(      GMP_RATS_mpq_struct *result,  
                       const GMP_RATS_mpq_struct *arg1,  
                       const GMP_RATS_mpq_struct *arg2)  
    {  
    GMP_RATS_mpq_struct negated_arg_2;  
   
    //Eyeball the input parameters.  
    assert(result != NULL);  
    assert(arg1   != NULL);  
    assert(arg2   != NULL);  
   
    //For the subtract function, we could do it directly,  
    //but might as well just define it recursively  
    //in terms of add.  We can't modify the inputs,  
    //so copy the second off and negate it.  All error  
    //flags and so forth will propagate automatically.  
    //  
    //Allocate space for the negated arg 2.  
    GMP_RATS_mpq_init(&negated_arg_2);  
   
    //Copy from the original.  
    GMP_RATS_mpq_copy(&negated_arg_2, arg2);  
   
    //Negate the copy.  Negating the numerator will  
    //do it.  
    GMP_INTS_mpz_negate(&(negated_arg_2.num));  
   
    //Make the add, which now is really a subtract.  
    GMP_RATS_mpq_add(result, arg1, &negated_arg_2);  
   
    //Destroy the temporary variable.  
    GMP_RATS_mpq_clear(&negated_arg_2);  
    }  
   
   
 //08/16/01: Visual inspection OK.  
 void GMP_RATS_mpq_mul(      GMP_RATS_mpq_struct *result,  
                       const GMP_RATS_mpq_struct *arg1,  
                       const GMP_RATS_mpq_struct *arg2)  
    {  
    //Eyeball the input parameters.  
    assert(result != NULL);  
    assert(arg1   != NULL);  
    assert(arg2   != NULL);  
   
    //If either rational number in the input is invalid,  
    //flag the result as invalid.  
    if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))  
       {  
       GMP_RATS_mpq_set_si(result, 1, 0);  
       }  
    else  
       {  
       //Rational number multiplication is a simple matter.  
       //Just multiply components.  Don't need to worry  
       //about rational numbers overlapping, as numerator  
       //operations and denominator operations are separate.  
       GMP_INTS_mpz_mul(&(result->num),  
                        &(arg1->num),  
                        &(arg2->num));  
       GMP_INTS_mpz_mul(&(result->den),  
                        &(arg1->den),  
                        &(arg2->den));  
   
       //Normalize it.  
       GMP_RATS_mpq_normalize(result);  
       }  
    }  
   
   
 //08/16/01: Visual inspection OK.  
 void GMP_RATS_mpq_div(      GMP_RATS_mpq_struct *result,  
                       const GMP_RATS_mpq_struct *arg1,  
                       const GMP_RATS_mpq_struct *arg2)  
    {  
    GMP_RATS_mpq_struct rv;  
   
    //Eyeball the input parameters.  
    assert(result != NULL);  
    assert(arg1   != NULL);  
    assert(arg2   != NULL);  
   
    //If either rational number in the input is invalid,  
    //flag the result as invalid.  
    if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))  
       {  
       GMP_RATS_mpq_set_si(result, 1, 0);  
       }  
    else  
       {  
       //Rational number division is a simple matter.  
       //Just multiply components.  We do need to worry  
       //about rational numbers overlapping, so must  
       //make a copy of the return value.  If denominator  
       //of return value is zero, it is NAN, but caller  
       //should detect this.  
       //  
       //Allocate return value.  
       GMP_RATS_mpq_init(&rv);  
   
       //Calculate quotient.  
       GMP_INTS_mpz_mul(&(rv.num),  
                        &(arg1->num),  
                        &(arg2->den));  
       GMP_INTS_mpz_mul(&(rv.den),  
                        &(arg1->den),  
                        &(arg2->num));  
   
       //Normalize quotient.  
       GMP_RATS_mpq_normalize(&rv);  
   
       //Copy to its destination.  
       GMP_RATS_mpq_copy(result, &rv);  
   
       //Deallocate temporary return value.  
       GMP_RATS_mpq_clear(&rv);  
       }  
    }  
   
   
 /******************************************************************/  
 /***  COMPARISON FUNCTIONS  ***************************************/  
 /******************************************************************/  
 //08/16/01: Visual inspection OK.  
 int GMP_RATS_mpq_cmp(const  GMP_RATS_mpq_struct *arg1,  
                      const  GMP_RATS_mpq_struct *arg2,  
                      int   *failure)  
    {  
    int arg1_sgn;  
    int arg2_sgn;  
    int rv, failure_rv;  
    GMP_INTS_mpz_struct prod1, prod2;  
   
    //Eyeball the input parameters.  Note that the third  
    //parameter may be NULL.  
    assert(arg1 != NULL);  
    assert(arg2 != NULL);  
   
    //If either of the input arguments are NAN, we  
    //cannot compare arguments.  We return 0, and it  
    //depends on the caller whether it is important  
    //that the comparison is bogus.  
    if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))  
       {  
       if (failure != NULL)  
          *failure = 1;  
       return(0);  
       }  
   
    //Calculate the sign of the left argument.  The encoding  
    //we'll use is -1 means negative, 0 means zero, and  
    //1 means positive.  
    if (GMP_INTS_mpz_is_zero(&(arg1->num)))  
       {  
       arg1_sgn = 0;  
       }  
    else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))  
       {  
       arg1_sgn = 1;  
       }  
    else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))  
       {  
       arg1_sgn = -1;  
       }  
    else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))  
       {  
       arg1_sgn = -1;  
       }  
    else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))  
       {  
       arg1_sgn = 1;  
       }  
   
    //Calculate the sign of the right argument.  The encoding  
    //we'll use is -1 means negative, 0 means zero, and  
    //1 means positive.  
    if (GMP_INTS_mpz_is_zero(&(arg2->num)))  
       {  
       arg2_sgn = 0;  
       }  
    else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))  
       {  
       arg2_sgn = 1;  
       }  
    else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))  
       {  
       arg2_sgn = -1;  
       }  
    else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))  
       {  
       arg2_sgn = -1;  
       }  
    else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))  
       {  
       arg2_sgn = 1;  
       }  
   
    //OK, can handle some simple cases where the signs of the  
    //operands are different or both are zero.  
    if ((arg1_sgn == 0) && (arg2_sgn == 0))  
       {  
       if (failure != NULL)  
          *failure = 0;  
       return(0);  
       }  
    else if ((arg1_sgn == -1) && (arg2_sgn > -1))  
       {  
       if (failure != NULL)  
          *failure = 0;  
       return(-1);  
       }  
    else if ((arg1_sgn == 0) && (arg2_sgn < 0))  
       {  
       if (failure != NULL)  
          *failure = 0;  
       return(1);  
       }  
    else if ((arg1_sgn == 0) && (arg2_sgn > 0))  
       {  
       if (failure != NULL)  
          *failure = 0;  
       return(-1);  
       }  
    else if ((arg1_sgn == 1) && (arg2_sgn < 1))  
       {  
       if (failure != NULL)  
          *failure = 0;  
       return(1);  
       }  
   
    //OK at this point, we cannot make a simple determination  
    //as to the relative ordering.  The signs of arg1 and  
    //arg2 are both the same, either both positive or both  
    //negative.  We have to do a multiplication to sort  
    //it out.  
    //  
    //Allocate the two integers to hold multiplication  
    //results.  
    GMP_INTS_mpz_init(&prod1);  
    GMP_INTS_mpz_init(&prod2);  
   
    //Cross-multiply to get relative magnitudes.  
    GMP_INTS_mpz_mul(&prod1, &(arg1->num), &(arg2->den));  
    GMP_INTS_mpz_mul(&prod2, &(arg1->den), &(arg2->num));  
     
    //Take absolute values.  
    GMP_INTS_mpz_abs(&prod1);  
    GMP_INTS_mpz_abs(&prod2);  
   
    //If we overflowed either multiplication and generated  
    //a NAN, we cannot complete the compare.  
    if (GMP_INTS_mpz_get_flags(&prod1) || GMP_INTS_mpz_get_flags(&prod2))  
       {  
       failure_rv = 1;  
       rv = 0;  
       }  
    //If both rational numbers were effectively positive, we can  
    //use the relative ordering of the products as the relative  
    //ordering of the rational numbers.  
    else if (arg1_sgn == 1)  
       {  
       //Compare the integers.  
       rv = GMP_INTS_mpz_cmp(&prod1, &prod2);  
   
       //Clamp the return value.  
       if (rv < 0)  
          rv = -1;  
       else if (rv == 0)  
          rv = 0;  
       else if (rv > 0)  
          rv = 1;  
   
       //There was no error.  
       failure_rv = 0;  
       }  
    else  
       {  
       //The only case that *should* allow us to be here is  
       //if the sign of both numbers is neg.  
       assert(arg1_sgn == -1);  
   
       //Compare the integers.  
       rv = GMP_INTS_mpz_cmp(&prod1, &prod2);  
   
       //Invert and clamp the return value.  
       if (rv < 0)  
          rv = 1;  
       else if (rv == 0)  
          rv = 0;  
       else if (rv > 0)  
          rv = -1;  
   
       //There was no error.  
       failure_rv = 0;  
       }  
   
    //Deallocate the two integers.  
    GMP_INTS_mpz_clear(&prod1);  
    GMP_INTS_mpz_clear(&prod2);  
   
    //Return the return values.  
    if (failure != NULL)  
       *failure = failure_rv;  
    return(rv);  
    }  
   
   
 /******************************************************************/  
 /***  VERSION CONTROL REPORTING FUNCTIONS  ************************/  
 /******************************************************************/  
 //08/07/01:  Visual inspection OK.  
 const char *GMP_RATS_cvcinfo(void)  
    {  
    return("$Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/c_datd/gmp_rats.c,v 1.10 2001/08/16 19:49:40 dtashley Exp $");  
    }  
   
   
 //08/07/01:  Visual inspection OK.  
 const char *GMP_RATS_hvcinfo(void)  
    {  
    return(GMP_RATS_H_VERSION);  
    }  
   
   
 //**************************************************************************  
 // $Log: gmp_rats.c,v $  
 // Revision 1.10  2001/08/16 19:49:40  dtashley  
 // Beginning to prepare for v1.05 release.  
 //  
 // Revision 1.9  2001/08/15 06:56:05  dtashley  
 // Substantial progress.  Safety check-in.  
 //  
 // Revision 1.8  2001/08/12 10:20:58  dtashley  
 // Safety check-in.  Substantial progress.  
 //  
 // Revision 1.7  2001/08/10 00:53:59  dtashley  
 // Completion of basic rational number arithmetic utilities and extensions.  
 //  
 // Revision 1.6  2001/08/08 02:16:51  dtashley  
 // Completion of RNRED utility and ARBINT RNRED Tcl extension.  
 //  
 // Revision 1.5  2001/08/07 10:42:48  dtashley  
 // Completion of CFRATNUM extensions and DOS command-line utility.  
 //  
 // Revision 1.4  2001/07/13 21:02:20  dtashley  
 // Version control reporting changes.  
 //  
 // Revision 1.3  2001/07/13 20:44:42  dtashley  
 // Changes, CVS keyword expansion test.  
 //  
 // Revision 1.2  2001/07/13 00:57:08  dtashley  
 // Safety check-in.  Substantial progress on port.  
 //  
 // Revision 1.1  2001/07/12 05:42:06  dtashley  
 // Initial checkin.  
 //  
 //**************************************************************************  
 // End of GMP_RATS.C.  
1    //$Header$
2    //-------------------------------------------------------------------------------------------------
3    //This file is part of "David T. Ashley's Shared Source Code", a set of shared components
4    //integrated into many of David T. Ashley's projects.
5    //-------------------------------------------------------------------------------------------------
6    //This source code and any program in which it is compiled/used is provided under the MIT License,
7    //reproduced below.
8    //-------------------------------------------------------------------------------------------------
9    //Permission is hereby granted, free of charge, to any person obtaining a copy of
10    //this software and associated documentation files(the "Software"), to deal in the
11    //Software without restriction, including without limitation the rights to use,
12    //copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the
13    //Software, and to permit persons to whom the Software is furnished to do so,
14    //subject to the following conditions :
15    //
16    //The above copyright notice and this permission notice shall be included in all
17    //copies or substantial portions of the Software.
18    //
19    //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20    //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21    //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
22    //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23    //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25    //SOFTWARE.
26    //-------------------------------------------------------------------------------------------------
27    #define MODULE_GMP_RATS
28    
29    #include <assert.h>
30    #include <stdio.h>
31    #include <string.h>
32    
33    #include "bstrfunc.h"
34    #include "charfunc.h"
35    #include "gmp_ints.h"
36    #include "gmp_rats.h"
37    
38    #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
39       #include "ccmalloc.h"
40    #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
41       #include "tclalloc.h"
42    #else
43       #include <malloc.h>
44    #endif
45    
46    
47    /******************************************************************/
48    /***  STATUS FUNCTIONS  *******************************************/
49    /******************************************************************/
50    //Functions in this category provide information about rational
51    //numbers.
52    //08/08/01:  Visual inspection OK.
53    int GMP_RATS_mpq_is_nan(const GMP_RATS_mpq_struct *rn)
54       {
55       assert(rn != NULL);
56    
57       //A rational number is NAN in one of two
58       //circumstances.  If either of the integer components
59       //is NAN, or else if there is a zero denominator.
60       if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
61          {
62          return(1);
63          }
64       if (GMP_INTS_mpz_is_zero(&(rn->den)))
65          {
66          return(1);
67          }
68    
69       //We're clean ...
70       return(0);
71       }
72    
73    
74    /******************************************************************/
75    /***  INITIALIZATION, CLEARING, AND SETTING FUNCTIONS  ************/
76    /******************************************************************/
77    //08/07/01:  Visual inspection OK.
78    void GMP_RATS_mpq_init(GMP_RATS_mpq_struct *arg)
79       {
80       //Eyeball the input parameter.
81       assert(arg != NULL);
82    
83       //Initialize the numerator and denominator.
84       GMP_INTS_mpz_init(&(arg->num));
85       GMP_INTS_mpz_init(&(arg->den));
86    
87       //Canonically, we must start off as 0/1--canonical zero.
88       GMP_INTS_mpz_set_ui(&(arg->num), 0);
89       GMP_INTS_mpz_set_ui(&(arg->den), 1);
90       }
91    
92    
93    //08/07/01:  Visual inspection OK.
94    void GMP_RATS_mpq_clear(GMP_RATS_mpq_struct *arg)
95       {
96       //Eyeball the input parameter.
97       assert(arg != NULL);
98    
99       //Clear the numerator and denominator.  The called functions
100       //will check for NULL pointers and so forth.
101       GMP_INTS_mpz_clear(&(arg->num));
102       GMP_INTS_mpz_clear(&(arg->den));
103       }
104    
105    
106    //08/07/01:  Visual inspection OK.
107    void GMP_RATS_mpq_set_si(GMP_RATS_mpq_struct *arg,
108                             int num,
109                             int den)
110       {
111       //Eyeball the input parameters.
112       assert(arg != NULL);
113    
114       //Set the numerator and denominator.
115       GMP_INTS_mpz_set_si(&(arg->num), num);
116       GMP_INTS_mpz_set_si(&(arg->den), den);
117       }
118    
119    
120    //08/08/01:  Visual inspection OK.
121    void GMP_RATS_mpq_copy(      GMP_RATS_mpq_struct *dst,
122                           const GMP_RATS_mpq_struct *src)
123       {
124       assert(dst != NULL);
125       assert(src != NULL);
126    
127       GMP_INTS_mpz_copy(&(dst->num), &(src->num));
128       GMP_INTS_mpz_copy(&(dst->den), &(src->den));
129       }
130    
131    
132    //08/13/01:  Visual inspection OK.
133    void GMP_RATS_mpq_swap( GMP_RATS_mpq_struct *a,
134                            GMP_RATS_mpq_struct *b)
135       {
136       assert(a != NULL);
137       assert(b != NULL);
138    
139       //Handle the swap by swapping integer components.
140       GMP_INTS_mpz_swap(&(a->num), &(b->num));
141       GMP_INTS_mpz_swap(&(a->den), &(b->den));
142       }
143    
144    
145    //08/13/01:  Visual inspection OK.
146    void GMP_RATS_mpq_swap_components(GMP_RATS_mpq_struct *arg)
147       {
148       assert(arg != NULL);
149    
150       GMP_INTS_mpz_swap(&(arg->num), &(arg->den));
151       }
152    
153    
154    //08/07/01:  Visual inspection OK.
155    void GMP_RATS_mpq_set_complex_slash_sepd_rat_num(const char *s,
156                                                     int *failure,
157                                                     GMP_RATS_mpq_struct *rn)
158       {
159       char *slash_posn, *numerator, *denominator;
160       size_t s_len, numerator_len, denominator_len;
161       size_t i;
162    
163       //Eyeball the input parameters.
164       assert(s != NULL);
165       assert(failure != NULL);
166       assert(rn != NULL);
167    
168       //Start off believing there is no failure.
169       *failure = 0;
170    
171       //Figure out if there is one and only one slash in the
172       //string.  If this condition isn't met, we cannot
173       //go further.
174       slash_posn = strchr(s, '/');
175       if (!slash_posn)
176          {
177          *failure = 1;
178          return;
179          }
180       if (strchr(slash_posn + 1, '/')) //There is a second occurence.
181          {
182          *failure = 1;
183          return;
184          }
185    
186       //At this point we have one and only one slash.
187       //Crack the string in two.  We must do this because the
188       //input is a constant string.  We are not allowed to touch it
189       //in the logical domain because of the "const" keyword.  We can't
190       //do this in the physical domain because the debugger will nail
191       //us for it.
192       s_len = strlen(s);
193       numerator_len = slash_posn - s;
194       denominator_len = strlen(slash_posn + 1);
195       #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
196          numerator   = CCMALLOC_malloc(sizeof(char) * (numerator_len   + 1));
197          denominator = CCMALLOC_malloc(sizeof(char) * (denominator_len + 1));
198       #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
199          numerator   = TclpAlloc(sizeof(char) * (numerator_len   + 1));
200          denominator = TclpAlloc(sizeof(char) * (denominator_len + 1));
201       #else
202          numerator   = malloc(sizeof(char) * (numerator_len   + 1));
203          denominator = malloc(sizeof(char) * (denominator_len + 1));
204       #endif
205    
206       assert(numerator   != NULL);
207       assert(denominator != NULL);
208    
209       for (i=0; i<numerator_len; i++)
210          {
211          numerator[i] = s[i];
212          }  
213       numerator[numerator_len] = 0;
214      
215       for (i=0; i<denominator_len; i++)
216          {
217          denominator[i] = s[slash_posn - s + 1 + i];
218          }
219       denominator[denominator_len] = 0;
220    
221       //Try to parse out the numerator as an arbitrary integer.
222       //If this can't be done, it is an immediate failure.
223       GMP_INTS_mpz_set_general_int(&(rn->num),
224                                    failure,
225                                    numerator);
226       if (*failure)
227          {
228          *failure = 1;  //Clamp to 1, don't know what non-zero value
229                         //was there.
230          goto ret_pt;
231          }
232    
233       //Try to parse out the denominator.
234       GMP_INTS_mpz_set_general_int(&(rn->den),
235                                    failure,
236                                    denominator);
237       if (*failure)
238          {
239          *failure = 1;  //Clamp to 1, don't know what non-zero value
240                         //was there.
241          goto ret_pt;
242          }
243    
244       //At this point, we have both a numerator and denominator.
245       //Clean up and return.
246       ret_pt:
247       #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
248          CCMALLOC_free(numerator);
249          CCMALLOC_free(denominator);
250       #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
251          TclpFree(numerator);
252          TclpFree(denominator);
253       #else
254          free(numerator);
255          free(denominator);
256       #endif
257       }
258    
259    
260    //08/07/01:  Visual inspection OK.
261    void GMP_RATS_mpq_set_sci_not_rat_num(const char *s,
262                                          int *failure,
263                                          GMP_RATS_mpq_struct *rn)
264       {
265       int parse_failure;
266          //Return code from the floating point parsing
267          //function.
268       char mant_sign;
269          //Sign character, if any, from the mantissa,
270          //or N otherwise.
271       size_t mant_bdp;
272          //The index to the start of the mantissa before
273          //the decimal point.
274       size_t mant_bdp_len;
275          //The length of the mantissa before the decimal
276          //point.  Zero means not defined, i.e. that
277          //no characters were parsed and interpreted as
278          //that part of a floating point number.
279       size_t mant_adp;
280       size_t mant_adp_len;
281          //Similar fields for after the decimal point.
282       char exp_sign;
283          //Sign of the exponent, if any, or N otherwise.
284       size_t exp;
285       size_t exp_len;
286          //Similar fields as to the mantissa, but for the
287          //exponent.
288       size_t si;
289          //Iteration variable.
290       int exponent_val;
291          //The value of the exponent.  We can't accept
292          //an exponent outside the range of a 24-bit
293          //signed integer.  The 24-bit limit is arbitrary.
294          //For one thing, it gives room to detect overflow
295          //as are adding and multiplying by 10.
296    
297       //Eyeball the input parameters.
298       assert(s != NULL);
299       assert(failure != NULL);
300       assert(rn != NULL);
301          //Subcomponents of the rational number will be checked as
302          //we make integer calls, if we're in debug mode.
303    
304       //Start off believing no failure.
305       *failure = 0;
306    
307       //Set the output to 0/1.  This is the default case for some
308       //steps below.
309       GMP_RATS_mpq_set_si(rn, 0, 1);
310    
311       //Attempt to parse the number as a general number
312       //in scientific notation.
313       BSTRFUNC_parse_gen_sci_not_num(s,
314                                      &parse_failure,
315                                      &mant_sign,
316                                      &mant_bdp,
317                                      &mant_bdp_len,
318                                      &mant_adp,
319                                      &mant_adp_len,
320                                      &exp_sign,
321                                      &exp,
322                                      &exp_len);
323    
324       //If it wouldn't parse as a general number, can't go further.
325       if (parse_failure)
326          {
327          *failure = 1;
328          return;
329          }
330       else
331          {
332          //The number parsed out.  The general strategy is to form a rational number
333          //consisting of the mantissa, with the decimal point shifted fully right, over
334          //a denominator of 1.  From there, we process the exponent and combine it with
335          //the number of characters after the decimal point to form a virtual exponent.
336          //If the exponent is positive, we multiply the numerator by the power of 10.
337          //If the exponent is negative, we multiply the denominator by that power of 10.
338    
339          //We want to trim the trailing zeros off of the portion of the mantissa after the
340          //decimal point.  We only need to back up indices, no need to make copies, etc.
341          //Note that it is possible that there are only zeros, in which case we'll end
342          //up with a length of zero.
343          while ((mant_adp_len > 0) && (s[mant_adp + mant_adp_len - 1]=='0'))
344             mant_adp_len--;
345    
346          //Trim the leading zeros off of the portion of the mantissa before the
347          //decimal point.  Note that it is possible that there is only a zero,
348          //so we may trim it down to nothing.
349          while ((mant_bdp_len > 0) && (s[mant_bdp]=='0'))
350             {
351             mant_bdp++;
352             mant_bdp_len--;
353             }
354    
355          //If we have only zeros in the mantissa, both before the
356          //decimal point and after, then we return 0.
357          if ((mant_bdp_len + mant_adp_len) == 0)
358             {
359             *failure = 0;
360             return;
361             }
362          
363          //Convert the numerator to an integer which represents the
364          //part before the mantissa and the part after the mantissa
365          //concatenated as an integer.  We could call a function to do
366          //this, but the function is not really any better in algorithm.
367          //We can do it ourselves.
368          GMP_INTS_mpz_set_ui(&(rn->num), 0);
369          for (si = 0; si < mant_bdp_len; si++)
370             {
371             int val;
372    
373             GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);
374             val = CHARFUNC_digit_to_val(s[mant_bdp + si]);
375             if (val >= 0)
376                GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);
377             }
378          for (si = 0; si < mant_adp_len; si++)
379             {
380             int val;
381    
382             GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);
383             val = CHARFUNC_digit_to_val(s[mant_adp + si]);
384             if (val >= 0)
385                GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);
386             }
387    
388          //The numerator should now have an integer which is
389          //The absolute value of the mantissa.  Process the possible
390          //sign.
391          if (mant_sign == '-')
392             GMP_INTS_mpz_negate(&(rn->num));
393    
394          //We now need to form a value from the exponent, if any.
395          //First, tackle the exponent.  Process the
396          //exponent into a signed integer.  We have to
397          //balk at anything outside of 24 bits.  The
398          //procedure used automatically handles
399          //leading zeros correctly.
400          exponent_val = 0;
401          for (si=exp; si<(exp+exp_len); si++)
402             {
403             int val;
404    
405             val = CHARFUNC_digit_to_val(s[si]);
406    
407             assert(val >= 0 && val <= 9);
408    
409             exponent_val *= 10;
410             exponent_val += val;
411    
412             if (((exp_sign=='-') && (exponent_val>8388608))
413                ||
414                ((exp_sign != '-') && (exponent_val>8388607)))
415                {
416                *failure = 1;
417                return;
418                }
419             }
420    
421          //If we're here, the exponent has been computed and
422          //is within 24 bits.  However, we need to adjust for
423          //the sign.
424          if (exp_sign == '-')
425             exponent_val = -exponent_val;
426    
427          //We need to adjust the exponent for the number of digits
428          //after the decimal point.
429          exponent_val -= mant_adp_len;  
430          
431          //Again, clip for size.
432          if ((exponent_val < -8388608) || (exponent_val > 8388607))
433             {
434             *failure = 1;
435             return;
436             }
437            
438          //There are two cases to consider.  If the exponent
439          //is positive, we need to multiply the numerator
440          //by 10 exponentiated to the power of the exponent.
441          //If the exponent is negative, we need to do the
442          //same thing to the denominator.  If the exponent
443          //is negative, we don't need to do anything.
444          if (exponent_val > 0)
445             {
446             GMP_INTS_mpz_struct k10, k10_exponentiated;
447    
448             GMP_INTS_mpz_init(&k10);
449             GMP_INTS_mpz_init(&k10_exponentiated);
450    
451             GMP_INTS_mpz_set_ui(&k10, 10);
452    
453             GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, exponent_val);
454    
455             GMP_INTS_mpz_mul(&(rn->num), &(rn->num), &k10_exponentiated);
456    
457             GMP_INTS_mpz_clear(&k10);
458             GMP_INTS_mpz_clear(&k10_exponentiated);
459    
460             *failure = 0;
461    
462             if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
463                *failure = 1;
464    
465             return;
466             }
467          else if (exponent_val < 0)
468             {
469             GMP_INTS_mpz_struct k10, k10_exponentiated;
470    
471             GMP_INTS_mpz_init(&k10);
472             GMP_INTS_mpz_init(&k10_exponentiated);
473    
474             GMP_INTS_mpz_set_ui(&k10, 10);
475    
476             GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, -exponent_val);
477    
478             GMP_INTS_mpz_mul(&(rn->den), &(rn->den), &k10_exponentiated);
479    
480             GMP_INTS_mpz_clear(&k10);
481             GMP_INTS_mpz_clear(&k10_exponentiated);
482    
483             *failure = 0;
484    
485             if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
486                *failure = 1;
487    
488             return;
489             }
490          }
491       }
492    
493    
494    //08/07/01:  Visual inspection OK.
495    void GMP_RATS_mpq_set_all_format_rat_num(const char *s,
496                                             int *failure,
497                                             GMP_RATS_mpq_struct *rn)
498       {
499       //Eyeball the input parameters.
500       assert(s != NULL);
501       assert(failure != NULL);
502       assert(rn != NULL);
503    
504       //Assume no failure.
505       *failure = 0;
506    
507       //Try in order to parse as integers with slash then
508       //as number in scientific notation.
509       GMP_RATS_mpq_set_complex_slash_sepd_rat_num(s,
510                                                   failure,
511                                                   rn);
512       if (!*failure)
513          return;
514    
515       GMP_RATS_mpq_set_sci_not_rat_num(s,
516                                        failure,
517                                        rn);
518    
519       if (*failure)
520          *failure = 1;  //Clamp output.
521       }
522    
523    
524    /******************************************************************/
525    /***  NORMALIZATION FUNCTIONS  ************************************/
526    /******************************************************************/
527    //08/07/01:  Visual inspection OK.
528    void GMP_RATS_mpq_normalize_sign(GMP_RATS_mpq_struct *rn)
529       {
530       //Eyeball the input.
531       assert(rn != NULL);
532    
533       if (GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))
534          {
535          //Both negative, can negate both, this leaves both positive,
536          //which is the normalized form for a positive rational
537          //number.
538          GMP_INTS_mpz_negate(&rn->num);
539          GMP_INTS_mpz_negate(&rn->den);
540          }
541       else if (!GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))
542          {
543          //Denominator neg, numerator non-neg, can negate both.  This
544          //will leave numerator neg, denominator pos, which is
545          //normalized form for negative rational number.
546          GMP_INTS_mpz_negate(&rn->num);
547          GMP_INTS_mpz_negate(&rn->den);
548          }    
549       }
550    
551    
552    //08/07/01:  Visual inspection OK.
553    void GMP_RATS_mpq_normalize(GMP_RATS_mpq_struct *rn)
554       {
555       //Eyeball the input.
556       assert(rn != NULL);
557    
558       //Cover some special cases.  If either component has flags
559       //set, don't even touch it.
560       if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
561          {
562          return;
563          }
564       //If the denominator is zero, normalize it to 1/0, the canonical
565       //for for an illegal rational number.
566       else if (GMP_INTS_mpz_is_zero(&(rn->den)))
567          {
568          GMP_RATS_mpq_set_si(rn, 1, 0);
569          return;
570          }
571       //If the numerator is zero, convert the number to the canonical
572       //form for zero of 0/1.
573       else if (GMP_INTS_mpz_is_zero(&(rn->num)))
574          {
575          GMP_RATS_mpq_set_si(rn, 0, 1);
576          return;
577          }
578       else
579          {
580          int num_is_neg;
581          int den_is_neg;
582          GMP_INTS_mpz_struct gcd, quotient, remainder;
583    
584          //Allocate space for the integers used.
585          GMP_INTS_mpz_init(&gcd);
586          GMP_INTS_mpz_init(&quotient);
587          GMP_INTS_mpz_init(&remainder);
588    
589          //This is the most normal case, where we need to
590          //look at reducing the numerator and denominator.
591          //One way to do it would be to obtain the g.c.d.
592          //and divide this out, and this is the route
593          //we'll take.  However, must grab out the sign.
594          if (GMP_INTS_mpz_is_neg(&(rn->num)))
595             {
596             num_is_neg = 1;
597             GMP_INTS_mpz_negate(&(rn->num));
598             }
599          else
600             {
601             num_is_neg = 0;
602             }
603    
604          if (GMP_INTS_mpz_is_neg(&(rn->den)))
605             {
606             den_is_neg = 1;
607             GMP_INTS_mpz_negate(&(rn->den));
608             }
609          else
610             {
611             den_is_neg = 0;
612             }
613    
614          //Calculate the GCD.
615          GMP_INTS_mpz_gcd(&gcd, &(rn->num), &(rn->den));
616    
617          //Divide the numerator by the GCD and store it
618          //back.
619          GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,
620                               &(rn->num), &gcd);
621          GMP_INTS_mpz_copy(&(rn->num), &quotient);
622    
623          //Divide the denominator by the GCD and store it
624          //back.
625          GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,
626                               &(rn->den), &gcd);
627          GMP_INTS_mpz_copy(&(rn->den), &quotient);
628    
629          //We now need to adjust the sign.  Both the
630          //numerator and denominator are definitely
631          //positive.  Need to make the numerator
632          //negative if either but not both of the
633          //original signs were negative.
634          if ((num_is_neg && !den_is_neg) || (!num_is_neg && den_is_neg))
635             {
636             GMP_INTS_mpz_negate(&(rn->num));
637             }
638    
639          //Deallocate space for the integers used.
640          GMP_INTS_mpz_clear(&gcd);
641          GMP_INTS_mpz_clear(&quotient);
642          GMP_INTS_mpz_clear(&remainder);
643    
644          return;
645          }    
646       }
647    
648    
649    /******************************************************************/
650    /***  ARITHMETIC FUNCTIONS  ***************************************/
651    /******************************************************************/
652    //08/08/01:  Visual inspection OK.
653    void GMP_RATS_mpq_add(      GMP_RATS_mpq_struct *result,
654                          const GMP_RATS_mpq_struct *arg1,
655                          const GMP_RATS_mpq_struct *arg2)
656       {
657       GMP_RATS_mpq_struct rv;
658       GMP_INTS_mpz_struct temp;
659    
660       //Eyeball the input parameters.
661       assert(result != NULL);
662       assert(arg1   != NULL);
663       assert(arg2   != NULL);
664    
665       //Generally speaking, we do not want to require that
666       //the arguments and the result be distinct, as this is
667       //too much of a restriction on the caller.  The approach
668       //taken, somewhat wasteful, is to allocate a place for
669       //the return value.
670       //
671       //For addition, if we are adding a/b and c/d, the
672       //result is necessarily algebraically
673       //(ad + cb)/bd.
674       //
675       //If either rational number in the input is invalid,
676       //flag the result as invalid.
677       if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
678          {
679          GMP_RATS_mpq_set_si(result, 1, 0);
680          }
681       else
682          {
683          //Both rational numbers are OK.  Can simply stage the
684          //result by the algebraic identity and then
685          //normalize it.  Only need one temporary variable.
686          //
687          //Initialize the rational number that we will use to
688          //hold return value in case it is the same as one
689          //or both of the arguments.
690          GMP_RATS_mpq_init(&rv);
691    
692          //Initialize the temporary integer.
693          GMP_INTS_mpz_init(&temp);
694    
695          //numerator = a * d
696          GMP_INTS_mpz_mul(&(rv.num), &(arg1->num), &(arg2->den));
697    
698          //temp = c * b
699          GMP_INTS_mpz_mul(&temp, &(arg2->num), &(arg1->den));
700    
701          //numerator = a * d + c * b
702          GMP_INTS_mpz_add(&(rv.num), &(rv.num), &temp);
703    
704          //denominator = b * d
705          GMP_INTS_mpz_mul(&(rv.den), &(arg1->den), &(arg2->den));
706    
707          //Copy the temporary result to the actual return value.
708          //Had to wait until now in case result was the same
709          //as either or both args.
710          GMP_RATS_mpq_copy(result, &rv);
711    
712          //Normalize the result.
713          GMP_RATS_mpq_normalize(result);
714    
715          //Free dynamic memory.
716          GMP_RATS_mpq_clear(&rv);
717          GMP_INTS_mpz_clear(&temp);
718          }
719       }
720    
721    
722    //08/08/01:  Visual inspection OK.
723    void GMP_RATS_mpq_sub(      GMP_RATS_mpq_struct *result,
724                          const GMP_RATS_mpq_struct *arg1,
725                          const GMP_RATS_mpq_struct *arg2)
726       {
727       GMP_RATS_mpq_struct negated_arg_2;
728    
729       //Eyeball the input parameters.
730       assert(result != NULL);
731       assert(arg1   != NULL);
732       assert(arg2   != NULL);
733    
734       //For the subtract function, we could do it directly,
735       //but might as well just define it recursively
736       //in terms of add.  We can't modify the inputs,
737       //so copy the second off and negate it.  All error
738       //flags and so forth will propagate automatically.
739       //
740       //Allocate space for the negated arg 2.
741       GMP_RATS_mpq_init(&negated_arg_2);
742    
743       //Copy from the original.
744       GMP_RATS_mpq_copy(&negated_arg_2, arg2);
745    
746       //Negate the copy.  Negating the numerator will
747       //do it.
748       GMP_INTS_mpz_negate(&(negated_arg_2.num));
749    
750       //Make the add, which now is really a subtract.
751       GMP_RATS_mpq_add(result, arg1, &negated_arg_2);
752    
753       //Destroy the temporary variable.
754       GMP_RATS_mpq_clear(&negated_arg_2);
755       }
756    
757    
758    //08/16/01: Visual inspection OK.
759    void GMP_RATS_mpq_mul(      GMP_RATS_mpq_struct *result,
760                          const GMP_RATS_mpq_struct *arg1,
761                          const GMP_RATS_mpq_struct *arg2)
762       {
763       //Eyeball the input parameters.
764       assert(result != NULL);
765       assert(arg1   != NULL);
766       assert(arg2   != NULL);
767    
768       //If either rational number in the input is invalid,
769       //flag the result as invalid.
770       if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
771          {
772          GMP_RATS_mpq_set_si(result, 1, 0);
773          }
774       else
775          {
776          //Rational number multiplication is a simple matter.
777          //Just multiply components.  Don't need to worry
778          //about rational numbers overlapping, as numerator
779          //operations and denominator operations are separate.
780          GMP_INTS_mpz_mul(&(result->num),
781                           &(arg1->num),
782                           &(arg2->num));
783          GMP_INTS_mpz_mul(&(result->den),
784                           &(arg1->den),
785                           &(arg2->den));
786    
787          //Normalize it.
788          GMP_RATS_mpq_normalize(result);
789          }
790       }
791    
792    
793    //08/16/01: Visual inspection OK.
794    void GMP_RATS_mpq_div(      GMP_RATS_mpq_struct *result,
795                          const GMP_RATS_mpq_struct *arg1,
796                          const GMP_RATS_mpq_struct *arg2)
797       {
798       GMP_RATS_mpq_struct rv;
799    
800       //Eyeball the input parameters.
801       assert(result != NULL);
802       assert(arg1   != NULL);
803       assert(arg2   != NULL);
804    
805       //If either rational number in the input is invalid,
806       //flag the result as invalid.
807       if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
808          {
809          GMP_RATS_mpq_set_si(result, 1, 0);
810          }
811       else
812          {
813          //Rational number division is a simple matter.
814          //Just multiply components.  We do need to worry
815          //about rational numbers overlapping, so must
816          //make a copy of the return value.  If denominator
817          //of return value is zero, it is NAN, but caller
818          //should detect this.
819          //
820          //Allocate return value.
821          GMP_RATS_mpq_init(&rv);
822    
823          //Calculate quotient.
824          GMP_INTS_mpz_mul(&(rv.num),
825                           &(arg1->num),
826                           &(arg2->den));
827          GMP_INTS_mpz_mul(&(rv.den),
828                           &(arg1->den),
829                           &(arg2->num));
830    
831          //Normalize quotient.
832          GMP_RATS_mpq_normalize(&rv);
833    
834          //Copy to its destination.
835          GMP_RATS_mpq_copy(result, &rv);
836    
837          //Deallocate temporary return value.
838          GMP_RATS_mpq_clear(&rv);
839          }
840       }
841    
842    
843    /******************************************************************/
844    /***  COMPARISON FUNCTIONS  ***************************************/
845    /******************************************************************/
846    //08/16/01: Visual inspection OK.
847    int GMP_RATS_mpq_cmp(const  GMP_RATS_mpq_struct *arg1,
848                         const  GMP_RATS_mpq_struct *arg2,
849                         int   *failure)
850       {
851       int arg1_sgn;
852       int arg2_sgn;
853       int rv, failure_rv;
854       GMP_INTS_mpz_struct prod1, prod2;
855    
856       //Eyeball the input parameters.  Note that the third
857       //parameter may be NULL.
858       assert(arg1 != NULL);
859       assert(arg2 != NULL);
860    
861       //If either of the input arguments are NAN, we
862       //cannot compare arguments.  We return 0, and it
863       //depends on the caller whether it is important
864       //that the comparison is bogus.
865       if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
866          {
867          if (failure != NULL)
868             *failure = 1;
869          return(0);
870          }
871    
872       //Calculate the sign of the left argument.  The encoding
873       //we'll use is -1 means negative, 0 means zero, and
874       //1 means positive.
875       if (GMP_INTS_mpz_is_zero(&(arg1->num)))
876          {
877          arg1_sgn = 0;
878          }
879       else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))
880          {
881          arg1_sgn = 1;
882          }
883       else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))
884          {
885          arg1_sgn = -1;
886          }
887       else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))
888          {
889          arg1_sgn = -1;
890          }
891       else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))
892          {
893          arg1_sgn = 1;
894          }
895    
896       //Calculate the sign of the right argument.  The encoding
897       //we'll use is -1 means negative, 0 means zero, and
898       //1 means positive.
899       if (GMP_INTS_mpz_is_zero(&(arg2->num)))
900          {
901          arg2_sgn = 0;
902          }
903       else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))
904          {
905          arg2_sgn = 1;
906          }
907       else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))
908          {
909          arg2_sgn = -1;
910          }
911       else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))
912          {
913          arg2_sgn = -1;
914          }
915       else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))
916          {
917          arg2_sgn = 1;
918          }
919    
920       //OK, can handle some simple cases where the signs of the
921       //operands are different or both are zero.
922       if ((arg1_sgn == 0) && (arg2_sgn == 0))
923          {
924          if (failure != NULL)
925             *failure = 0;
926          return(0);
927          }
928       else if ((arg1_sgn == -1) && (arg2_sgn > -1))
929          {
930          if (failure != NULL)
931             *failure = 0;
932          return(-1);
933          }
934       else if ((arg1_sgn == 0) && (arg2_sgn < 0))
935          {
936          if (failure != NULL)
937             *failure = 0;
938          return(1);
939          }
940       else if ((arg1_sgn == 0) && (arg2_sgn > 0))
941          {
942          if (failure != NULL)
943             *failure = 0;
944          return(-1);
945          }
946       else if ((arg1_sgn == 1) && (arg2_sgn < 1))
947          {
948          if (failure != NULL)
949             *failure = 0;
950          return(1);
951          }
952    
953       //OK at this point, we cannot make a simple determination
954       //as to the relative ordering.  The signs of arg1 and
955       //arg2 are both the same, either both positive or both
956       //negative.  We have to do a multiplication to sort
957       //it out.
958       //
959       //Allocate the two integers to hold multiplication
960       //results.
961       GMP_INTS_mpz_init(&prod1);
962       GMP_INTS_mpz_init(&prod2);
963    
964       //Cross-multiply to get relative magnitudes.
965       GMP_INTS_mpz_mul(&prod1, &(arg1->num), &(arg2->den));
966       GMP_INTS_mpz_mul(&prod2, &(arg1->den), &(arg2->num));
967      
968       //Take absolute values.
969       GMP_INTS_mpz_abs(&prod1);
970       GMP_INTS_mpz_abs(&prod2);
971    
972       //If we overflowed either multiplication and generated
973       //a NAN, we cannot complete the compare.
974       if (GMP_INTS_mpz_get_flags(&prod1) || GMP_INTS_mpz_get_flags(&prod2))
975          {
976          failure_rv = 1;
977          rv = 0;
978          }
979       //If both rational numbers were effectively positive, we can
980       //use the relative ordering of the products as the relative
981       //ordering of the rational numbers.
982       else if (arg1_sgn == 1)
983          {
984          //Compare the integers.
985          rv = GMP_INTS_mpz_cmp(&prod1, &prod2);
986    
987          //Clamp the return value.
988          if (rv < 0)
989             rv = -1;
990          else if (rv == 0)
991             rv = 0;
992          else if (rv > 0)
993             rv = 1;
994    
995          //There was no error.
996          failure_rv = 0;
997          }
998       else
999          {
1000          //The only case that *should* allow us to be here is
1001          //if the sign of both numbers is neg.
1002          assert(arg1_sgn == -1);
1003    
1004          //Compare the integers.
1005          rv = GMP_INTS_mpz_cmp(&prod1, &prod2);
1006    
1007          //Invert and clamp the return value.
1008          if (rv < 0)
1009             rv = 1;
1010          else if (rv == 0)
1011             rv = 0;
1012          else if (rv > 0)
1013             rv = -1;
1014    
1015          //There was no error.
1016          failure_rv = 0;
1017          }
1018    
1019       //Deallocate the two integers.
1020       GMP_INTS_mpz_clear(&prod1);
1021       GMP_INTS_mpz_clear(&prod2);
1022    
1023       //Return the return values.
1024       if (failure != NULL)
1025          *failure = failure_rv;
1026       return(rv);
1027       }
1028    
1029    
1030    /******************************************************************/
1031    /***  VERSION CONTROL REPORTING FUNCTIONS  ************************/
1032    /******************************************************************/
1033    //08/07/01:  Visual inspection OK.
1034    const char *GMP_RATS_cvcinfo(void)
1035       {
1036       return("$Header$");
1037       }
1038    
1039    
1040    //08/07/01:  Visual inspection OK.
1041    const char *GMP_RATS_hvcinfo(void)
1042       {
1043       return(GMP_RATS_H_VERSION);
1044       }
1045    
1046    //End of gmp_rats.c.

Legend:
Removed from v.25  
changed lines
  Added in v.90

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25