pax_global_header00006660000000000000000000000064132524120770014515gustar00rootroot0000000000000052 comment=c076531c57bf328fa077d2e3f6e0ae2acbda6e6c deepin-calculator-1.0.2/000077500000000000000000000000001325241207700151105ustar00rootroot00000000000000deepin-calculator-1.0.2/.clog.toml000066400000000000000000000001721325241207700170070ustar00rootroot00000000000000[clog] repository = "https://github.com/linuxdeepin/deepin-calculator" from-latest-tag = true changelog = "CHANGELOG.md" deepin-calculator-1.0.2/.gitignore000066400000000000000000000000661325241207700171020ustar00rootroot00000000000000Makefile moc_*.o moc_*.cpp *.o *.qm build/ *.pro.user deepin-calculator-1.0.2/.tx/000077500000000000000000000000001325241207700156215ustar00rootroot00000000000000deepin-calculator-1.0.2/.tx/config000066400000000000000000000005311325241207700170100ustar00rootroot00000000000000[main] host = https://www.transifex.com minimum_perc = 80 mode = developer [deepin-calculator.deepin-calculator] file_filter = translations/deepin-calculator_.ts source_file = translations/deepin-calculator.ts source_lang = en type = QT [deepin-calculator.desktop] source_file = deepin-calculator.desktop source_lang = en type = DESKTOP deepin-calculator-1.0.2/CHANGELOG.md000066400000000000000000000074721325241207700167330ustar00rootroot00000000000000## 1.0.2 adjust detail ## 1.0.1 (2017-12-07) #### Features * use fixed fonts for listview. ([aefea6e0](https://github.com/linuxdeepin/deepin-calculator/commit/aefea6e028caf7e1c113a7271eac1a4cd32e4cb5)) #### Bug Fixes * precision of the previous answer. ([81ff49a5](https://github.com/linuxdeepin/deepin-calculator/commit/81ff49a5481f8d2f84d02064e19c8d38cbfb9598)) ## 1.0.0 (2017-11-30) #### Bug Fixes * listview color. ([744a92a5](https://github.com/linuxdeepin/deepin-calculator/commit/744a92a5fcb0fd146785ddfd84f1a42a219f5389)) * history text pos. ([dbf187ad](https://github.com/linuxdeepin/deepin-calculator/commit/dbf187ada81094afb8c44b1eeb039d0f8bcf8225)) * mult dot not error. ([31636fc7](https://github.com/linuxdeepin/deepin-calculator/commit/31636fc754643cd70d993e66abdfbf8f21cd8fcc)) * inputEdit position ([9e14a700](https://github.com/linuxdeepin/deepin-calculator/commit/9e14a7008440cdf3e008e5dc4f7f76e288a19b72)) * inputEdit cursor position. ([abf3bbb5](https://github.com/linuxdeepin/deepin-calculator/commit/abf3bbb55cc54e4f3c55aa499550c06cf8538708)) * **background:** repeated rendering of background color ([80e5de0d](https://github.com/linuxdeepin/deepin-calculator/commit/80e5de0d19d44f1af10822ed92e132d1f250c6ba)) * **config:** parameter error ([e5e02e73](https://github.com/linuxdeepin/deepin-calculator/commit/e5e02e733d88f484a1ffc4aed649f13c228b056c)) * **inputEdit:** paired brackets. ([ecee0a7a](https://github.com/linuxdeepin/deepin-calculator/commit/ecee0a7aaa96d3346a9786c29c50a90e2a95bbbc)) * **title:** use correct icon ([9ee9c185](https://github.com/linuxdeepin/deepin-calculator/commit/9ee9c1850cd2259d60948c415d1f7016daf7300c)) #### Features * modify width for listview. ([f4750541](https://github.com/linuxdeepin/deepin-calculator/commit/f4750541a2e3336ae23ef8e807769747d3f8828c)) * double select ([79cd8bf8](https://github.com/linuxdeepin/deepin-calculator/commit/79cd8bf88fff0978a5db69efe0483b662c7d6f2f)) * add error font color && upgrade help manual. ([040f338c](https://github.com/linuxdeepin/deepin-calculator/commit/040f338ca9da1557c548eb0172753bf11bd299a0)) * modify max value of point. ([9bcbec91](https://github.com/linuxdeepin/deepin-calculator/commit/9bcbec9188e3c02bb8b945d28eb13767aaf9ca2e)) * add thousands separators. ([ead7ec78](https://github.com/linuxdeepin/deepin-calculator/commit/ead7ec7885a7f116d4a07d3b71fcfbbad7587c2e)) * press mult sign twice trigger pow. ([6e8327f0](https://github.com/linuxdeepin/deepin-calculator/commit/6e8327f085e7b988e15d6c173495e2d87a0abfa6)) * optimize editor. ([c414f2ff](https://github.com/linuxdeepin/deepin-calculator/commit/c414f2ffe7dfcbe81e7ae130cac6a91fa3bfd572)) * add help manual. ([0a85e03a](https://github.com/linuxdeepin/deepin-calculator/commit/0a85e03a148220db69195b839a7670099fc4785a)) * add thousands separators func. ([0c8549d4](https://github.com/linuxdeepin/deepin-calculator/commit/0c8549d4503aea902de6c458fb79b0bee50f843e)) * add icon install. ([27d3ae91](https://github.com/linuxdeepin/deepin-calculator/commit/27d3ae91b3d128e754f9c7140f9a401b0ff6249d)) * add service file. ([5c808d89](https://github.com/linuxdeepin/deepin-calculator/commit/5c808d89d30ccc3f90ea584b2dd0333a079a243a)) * make font size of edit fit text content. ([c4810e41](https://github.com/linuxdeepin/deepin-calculator/commit/c4810e41707da3ff36078a1640645065645212c2)) * **algorithm:** support percent sign(%) symbolic operation. ([6b714cfc](https://github.com/linuxdeepin/deepin-calculator/commit/6b714cfc00e7f62235a3b8813d469ade71ed4c9a)) * **mainwindow:** * optimize slots. ([3e971c08](https://github.com/linuxdeepin/deepin-calculator/commit/3e971c0894904ace52b4f8e2c1562961f276c309)) * use QSignalMapper ([01dc666f](https://github.com/linuxdeepin/deepin-calculator/commit/01dc666fde6c85667a6ad11eeb85ade1b79a68e8)) deepin-calculator-1.0.2/LICENSE000066400000000000000000001045051325241207700161220ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. 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 . 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: {project} Copyright (C) {year} {fullname} 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 . 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 . deepin-calculator-1.0.2/README.md000066400000000000000000000016521325241207700163730ustar00rootroot00000000000000# Deepin Calculator Deepin calculator is an easy to use calculator for ordinary users. ## Dependencies * sudo apt install libdtkwidget-dev libqt5svg5-dev qttools5-dev-tools ## Installation * mkdir build * cd build * qmake .. * make ## Usage * ./deepin-calculator ## Getting help Any usage issues can ask for help via * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) * [IRC channel](https://webchat.freenode.net/?channels=deepin) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## Getting involved We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) ## License Deepin Calculator is licensed under [GPLv3](LICENSE). deepin-calculator-1.0.2/com.deepin.Calculator.service000066400000000000000000000001131325241207700225760ustar00rootroot00000000000000[D-BUS Service] Name=com.deepin.Calculator Exec=/usr/bin/deepin-calculator deepin-calculator-1.0.2/core/000077500000000000000000000000001325241207700160405ustar00rootroot00000000000000deepin-calculator-1.0.2/core/constants.cpp000066400000000000000000001636441325241207700205760ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2007 Ariya Hidayat // Copyright (C) 2007, 2009, 2011, 2013, 2016 @heldercorreia // Copyright (C) 2009 Andreas Scherer // Copyright (C) 2016 Hadrien Theveneau // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "core/constants.h" #include "core/numberformatter.h" #include "math/hmath.h" #include #include static Constants* s_constantsInstance = nullptr; static void s_deleteConstants() { delete s_constantsInstance; } struct Constants::Private { QStringList categories; QList list; void populate(); void retranslateText(); }; // UNCERTAINTY and CHECKEC reserved for future use #define PUSH_CONSTANT_CODATA(NAME,VALUE,UNIT,UNCERTAINTY,CHECKED) \ c.value = QLatin1String(VALUE); \ c.unit = QString::fromUtf8(UNIT); \ list << c; #define PUSH_CONSTANT(NAME,VALUE,UNIT) \ c.value = QLatin1String(VALUE); \ c.unit = QString::fromUtf8(UNIT); \ list << c; #define PUSH_CONSTANT_NO_UNIT(NAME,VALUE) \ c.value = QLatin1String(VALUE); \ list << c; #define I18N_CONSTANT(NAME) \ i->name = NAME; \ i->category = cat; \ ++i; #define I18N_CONSTANT_DAYS(NAME) \ i->unit = days; \ I18N_CONSTANT(NAME) void Constants::Private::populate() { Constant c; // CODATA Internationally recommended values of the Fundamental Physical Constants // Constants not yet included, to be included in future releases (TODO) // From: http://physics.nist.gov/cuu/Constants/ // Date: 2016-03-28 // Quantity Value Uncertainty Unit // ----------------------------------------------------------------------------------------------------------------------------- // alpha particle-electron mass ratio 7294.299 541 36 0.000 000 24 // alpha particle mass 6.644 657 230 e-27 0.000 000 082 e-27 kg // alpha particle mass energy equivalent 5.971 920 097 e-10 0.000 000 073 e-10 J // alpha particle mass energy equivalent in MeV 3727.379 378 0.000 023 MeV // alpha particle mass in u 4.001 506 179 127 0.000 000 000 063 u // alpha particle molar mass 4.001 506 179 127 e-3 0.000 000 000 063 e-3 kg mol^-1 // alpha particle-proton mass ratio 3.972 599 689 07 0.000 000 000 36 // Angstrom star 1.000 014 95 e-10 0.000 000 90 e-10 m // atomic mass constant energy equivalent 1.492 418 062 e-10 0.000 000 018 e-10 J // atomic mass constant energy equivalent in MeV 931.494 0954 0.000 0057 MeV // atomic mass unit-electron volt relationship 931.494 0954 e6 0.000 0057 e6 eV // atomic mass unit-hartree relationship 3.423 177 6902 e7 0.000 000 0016 e7 E_h // atomic mass unit-hertz relationship 2.252 342 7206 e23 0.000 000 0010 e23 Hz // atomic mass unit-inverse meter relationship 7.513 006 6166 e14 0.000 000 0034 e14 m^-1 // atomic mass unit-joule relationship 1.492 418 062 e-10 0.000 000 018 e-10 J // atomic mass unit-kelvin relationship 1.080 954 38 e13 0.000 000 62 e13 K // atomic mass unit-kilogram relationship 1.660 539 040 e-27 0.000 000 020 e-27 kg // atomic unit of 1st hyperpolarizability 3.206 361 329 e-53 0.000 000 020 e-53 C^3 m^3 J^-2 // atomic unit of 2nd hyperpolarizability 6.235 380 085 e-65 0.000 000 077 e-65 C^4 m^4 J^-3 // atomic unit of action 1.054 571 800 e-34 0.000 000 013 e-34 J s // atomic unit of charge 1.602 176 6208 e-19 0.000 000 0098 e-19 C // atomic unit of charge density 1.081 202 3770 e12 0.000 000 0067 e12 C m^-3 // atomic unit of current 6.623 618 183 e-3 0.000 000 041 e-3 A // atomic unit of electric dipole mom. 8.478 353 552 e-30 0.000 000 052 e-30 C m // atomic unit of electric field 5.142 206 707 e11 0.000 000 032 e11 V m^-1 // atomic unit of electric field gradient 9.717 362 356 e21 0.000 000 060 e21 V m^-2 // atomic unit of electric polarizability 1.648 777 2731 e-41 0.000 000 0011 e-41 C^2 m^2 J^-1 // atomic unit of electric potential 27.211 386 02 0.000 000 17 V // atomic unit of electric quadrupole mom. 4.486 551 484 e-40 0.000 000 028 e-40 C m^2 // atomic unit of energy 4.359 744 650 e-18 0.000 000 054 e-18 J // atomic unit of force 8.238 723 36 e-8 0.000 000 10 e-8 N // atomic unit of length 0.529 177 210 67 e-10 0.000 000 000 12 e-10 m // atomic unit of mag. dipole mom. 1.854 801 999 e-23 0.000 000 011 e-23 J T^-1 // atomic unit of mag. flux density 2.350 517 550 e5 0.000 000 014 e5 T // atomic unit of magnetizability 7.891 036 5886 e-29 0.000 000 0090 e-29 J T^-2 // atomic unit of mass 9.109 383 56 e-31 0.000 000 11 e-31 kg // atomic unit of mom.um 1.992 851 882 e-24 0.000 000 024 e-24 kg m s^-1 // atomic unit of permittivity 1.112 650 056... e-10 (exact) F m^-1 // atomic unit of time 2.418 884 326 509 e-17 0.000 000 000 014 e-17 s // atomic unit of velocity 2.187 691 262 77 e6 0.000 000 000 50 e6 m s^-1 // Bohr magneton in eV/T 5.788 381 8012 e-5 0.000 000 0026 e-5 eV T^-1 // Bohr magneton in Hz/T 13.996 245 042 e9 0.000 000 086 e9 Hz T^-1 // Bohr magneton in inverse meters per tesla 46.686 448 14 0.000 000 29 m^-1 T^-1 // Bohr magneton in K/T 0.671 714 05 0.000 000 39 K T^-1 // Boltzmann constant in eV/K 8.617 3303 e-5 0.000 0050 e-5 eV K^-1 // Boltzmann constant in Hz/K 2.083 6612 e10 0.000 0012 e10 Hz K^-1 // Boltzmann constant in inverse meters per kelvin 69.503 457 0.000 040 m^-1 K^-1 // classical electron radius 2.817 940 3227 e-15 0.000 000 0019 e-15 m // Cu x unit 1.002 076 97 e-13 0.000 000 28 e-13 m // deuteron-electron mag. mom. ratio -4.664 345 535 e-4 0.000 000 026 e-4 // deuteron-electron mass ratio 3670.482 967 85 0.000 000 13 // deuteron g factor 0.857 438 2311 0.000 000 0048 // deuteron mag. mom. 0.433 073 5040 e-26 0.000 000 0036 e-26 J T^-1 // deuteron mag. mom. to Bohr magneton ratio 0.466 975 4554 e-3 0.000 000 0026 e-3 // deuteron mag. mom. to nuclear magneton ratio 0.857 438 2311 0.000 000 0048 // deuteron mass 3.343 583 719 e-27 0.000 000 041 e-27 kg // deuteron mass energy equivalent 3.005 063 183 e-10 0.000 000 037 e-10 J // deuteron mass energy equivalent in MeV 1875.612 928 0.000 012 MeV // deuteron mass in u 2.013 553 212 745 0.000 000 000 040 u // deuteron molar mass 2.013 553 212 745 e-3 0.000 000 000 040 e-3 kg mol^-1 // deuteron-neutron mag. mom. ratio -0.448 206 52 0.000 000 11 // deuteron-proton mag. mom. ratio 0.307 012 2077 0.000 000 0015 // deuteron-proton mass ratio 1.999 007 500 87 0.000 000 000 19 // deuteron rms charge radius 2.1413 e-15 0.0025 e-15 m // electron charge to mass quotient -1.758 820 024 e11 0.000 000 011 e11 C kg^-1 // electron-deuteron mag. mom. ratio -2143.923 499 0.000 012 // electron-deuteron mass ratio 2.724 437 107 484 e-4 0.000 000 000 096 e-4 // electron g factor -2.002 319 304 361 82 0.000 000 000 000 52 // electron gyromag. ratio 1.760 859 644 e11 0.000 000 011 e11 s^-1 T^-1 // electron gyromag. ratio over 2 pi 28 024.951 64 0.000 17 MHz T^-1 // electron-helion mass ratio 1.819 543 074 854 e-4 0.000 000 000 088 e-4 // electron mag. mom. -928.476 4620 e-26 0.000 0057 e-26 J T^-1 // electron mag. mom. anomaly 1.159 652 180 91 e-3 0.000 000 000 26 e-3 // electron mag. mom. to Bohr magneton ratio -1.001 159 652 180 91 0.000 000 000 000 26 // electron mag. mom. to nuclear magneton ratio -1838.281 972 34 0.000 000 17 // electron mass energy equivalent 8.187 105 65 e-14 0.000 000 10 e-14 J // electron mass in u 5.485 799 090 70 e-4 0.000 000 000 16 e-4 u // electron molar mass 5.485 799 090 70 e-7 0.000 000 000 16 e-7 kg mol^-1 // electron-muon mag. mom. ratio 206.766 9880 0.000 0046 // electron-muon mass ratio 4.836 331 70 e-3 0.000 000 11 e-3 // electron-neutron mag. mom. ratio 960.920 50 0.000 23 // electron-neutron mass ratio 5.438 673 4428 e-4 0.000 000 0027 e-4 // electron-proton mag. mom. ratio -658.210 6866 0.000 0020 // electron-proton mass ratio 5.446 170 213 52 e-4 0.000 000 000 52 e-4 // electron-tau mass ratio 2.875 92 e-4 0.000 26 e-4 // electron to alpha particle mass ratio 1.370 933 554 798 e-4 0.000 000 000 045 e-4 // electron to shielded helion mag. mom. ratio 864.058 257 0.000 010 // electron to shielded proton mag. mom. ratio -658.227 5971 0.000 0072 // electron-triton mass ratio 1.819 200 062 203 e-4 0.000 000 000 084 e-4 // electron volt-atomic mass unit relationship 1.073 544 1105 e-9 0.000 000 0066 e-9 u // electron volt-hartree relationship 3.674 932 248 e-2 0.000 000 023 e-2 E_h // electron volt-hertz relationship 2.417 989 262 e14 0.000 000 015 e14 Hz // electron volt-inverse meter relationship 8.065 544 005 e5 0.000 000 050 e5 m^-1 // electron volt-joule relationship 1.602 176 6208 e-19 0.000 000 0098 e-19 J // electron volt-kelvin relationship 1.160 452 21 e4 0.000 000 67 e4 K // electron volt-kilogram relationship 1.782 661 907 e-36 0.000 000 011 e-36 kg // elementary charge over h 2.417 989 262 e14 0.000 000 015 e14 A J^-1 // hartree-atomic mass unit relationship 2.921 262 3197 e-8 0.000 000 0013 e-8 u // hartree-electron volt relationship 27.211 386 02 0.000 000 17 eV // hartree-hertz relationship 6.579 683 920 711 e15 0.000 000 000 039 e15 Hz // hartree-inverse meter relationship 2.194 746 313 702 e7 0.000 000 000 013 e7 m^-1 // hartree-joule relationship 4.359 744 650 e-18 0.000 000 054 e-18 J // hartree-kelvin relationship 3.157 7513 e5 0.000 0018 e5 K // hartree-kilogram relationship 4.850 870 129 e-35 0.000 000 060 e-35 kg // helion-electron mass ratio 5495.885 279 22 0.000 000 27 // helion g factor -4.255 250 616 0.000 000 050 // helion mag. mom. -1.074 617 522 e-26 0.000 000 014 e-26 J T^-1 // helion mag. mom. to Bohr magneton ratio -1.158 740 958 e-3 0.000 000 014 e-3 // helion mag. mom. to nuclear magneton ratio -2.127 625 308 0.000 000 025 // helion mass 5.006 412 700 e-27 0.000 000 062 e-27 kg // helion mass energy equivalent 4.499 539 341 e-10 0.000 000 055 e-10 J // helion mass energy equivalent in MeV 2808.391 586 0.000 017 MeV // helion mass in u 3.014 932 246 73 0.000 000 000 12 u // helion molar mass 3.014 932 246 73 e-3 0.000 000 000 12 e-3 kg mol^-1 // helion-proton mass ratio 2.993 152 670 46 0.000 000 000 29 // hertz-atomic mass unit relationship 4.439 821 6616 e-24 0.000 000 0020 e-24 u // hertz-electron volt relationship 4.135 667 662 e-15 0.000 000 025 e-15 eV // hertz-hartree relationship 1.519 829 846 0088 e-16 0.000 000 000 0090 e-16 E_h // hertz-inverse meter relationship 3.335 640 951... e-9 (exact) m^-1 // hertz-joule relationship 6.626 070 040 e-34 0.000 000 081 e-34 J // hertz-kelvin relationship 4.799 2447 e-11 0.000 0028 e-11 K // hertz-kilogram relationship 7.372 497 201 e-51 0.000 000 091 e-51 kg // inverse fine-structure constant 137.035 999 139 0.000 000 031 // inverse meter-atomic mass unit relationship 1.331 025 049 00 e-15 0.000 000 000 61 e-15 u // inverse meter-electron volt relationship 1.239 841 9739 e-6 0.000 000 0076 e-6 eV // inverse meter-hartree relationship 4.556 335 252 767 e-8 0.000 000 000 027 e-8 E_h // inverse meter-hertz relationship 299 792 458 (exact) Hz // inverse meter-joule relationship 1.986 445 824 e-25 0.000 000 024 e-25 J // inverse meter-kelvin relationship 1.438 777 36 e-2 0.000 000 83 e-2 K // inverse meter-kilogram relationship 2.210 219 057 e-42 0.000 000 027 e-42 kg // joule-atomic mass unit relationship 6.700 535 363 e9 0.000 000 082 e9 u // joule-electron volt relationship 6.241 509 126 e18 0.000 000 038 e18 eV // joule-hartree relationship 2.293 712 317 e17 0.000 000 028 e17 E_h // joule-hertz relationship 1.509 190 205 e33 0.000 000 019 e33 Hz // joule-inverse meter relationship 5.034 116 651 e24 0.000 000 062 e24 m^-1 // joule-kelvin relationship 7.242 9731 e22 0.000 0042 e22 K // joule-kilogram relationship 1.112 650 056... e-17 (exact) kg // kelvin-atomic mass unit relationship 9.251 0842 e-14 0.000 0053 e-14 u // kelvin-electron volt relationship 8.617 3303 e-5 0.000 0050 e-5 eV // kelvin-hartree relationship 3.166 8105 e-6 0.000 0018 e-6 E_h // kelvin-hertz relationship 2.083 6612 e10 0.000 0012 e10 Hz // kelvin-inverse meter relationship 69.503 457 0.000 040 m^-1 // kelvin-joule relationship 1.380 648 52 e-23 0.000 000 79 e-23 J // kelvin-kilogram relationship 1.536 178 65 e-40 0.000 000 88 e-40 kg // kilogram-atomic mass unit relationship 6.022 140 857 e26 0.000 000 074 e26 u // kilogram-electron volt relationship 5.609 588 650 e35 0.000 000 034 e35 eV // kilogram-hartree relationship 2.061 485 823 e34 0.000 000 025 e34 E_h // kilogram-hertz relationship 1.356 392 512 e50 0.000 000 017 e50 Hz // kilogram-inverse meter relationship 4.524 438 411 e41 0.000 000 056 e41 m^-1 // kilogram-joule relationship 8.987 551 787... e16 (exact) J // kilogram-kelvin relationship 6.509 6595 e39 0.000 0037 e39 K // lattice parameter of silicon 543.102 0504 e-12 0.000 0089 e-12 m // molar mass constant 1 e-3 (exact) kg mol^-1 // molar mass of carbon-12 12 e-3 (exact) kg mol^-1 // molar Planck constant times c 0.119 626 565 582 0.000 000 000 054 J m mol^-1 // molar volume of ideal gas (273.15 K, 100 kPa) 22.710 947 e-3 0.000 013 e-3 m^3 mol^-1 // molar volume of ideal gas (273.15 K, 101.325 kPa) 22.413 962 e-3 0.000 013 e-3 m^3 mol^-1 // molar volume of silicon 12.058 832 14 e-6 0.000 000 61 e-6 m^3 mol^-1 // Mo x unit 1.002 099 52 e-13 0.000 000 53 e-13 m // muon Compton wavelength 11.734 441 11 e-15 0.000 000 26 e-15 m // muon Compton wavelength over 2 pi 1.867 594 308 e-15 0.000 000 042 e-15 m // muon-electron mass ratio 206.768 2826 0.000 0046 // muon g factor -2.002 331 8418 0.000 000 0013 // muon mag. mom. -4.490 448 26 e-26 0.000 000 10 e-26 J T^-1 // muon mag. mom. anomaly 1.165 920 89 e-3 0.000 000 63 e-3 // muon mag. mom. to Bohr magneton ratio -4.841 970 48 e-3 0.000 000 11 e-3 // muon mag. mom. to nuclear magneton ratio -8.890 597 05 0.000 000 20 // muon mass energy equivalent 1.692 833 774 e-11 0.000 000 043 e-11 J // muon mass in u 0.113 428 9257 0.000 000 0025 u // muon molar mass 0.113 428 9257 e-3 0.000 000 0025 e-3 kg mol^-1 // muon-neutron mass ratio 0.112 454 5167 0.000 000 0025 // muon-proton mag. mom. ratio -3.183 345 142 0.000 000 071 // muon-proton mass ratio 0.112 609 5262 0.000 000 0025 // muon-tau mass ratio 5.946 49 e-2 0.000 54 e-2 // natural unit of action 1.054 571 800 e-34 0.000 000 013 e-34 J s // natural unit of action in eV s 6.582 119 514 e-16 0.000 000 040 e-16 eV s // natural unit of energy 8.187 105 65 e-14 0.000 000 10 e-14 J // natural unit of energy in MeV 0.510 998 9461 0.000 000 0031 MeV // natural unit of length 386.159 267 64 e-15 0.000 000 18 e-15 m // natural unit of mass 9.109 383 56 e-31 0.000 000 11 e-31 kg // natural unit of mom.um 2.730 924 488 e-22 0.000 000 034 e-22 kg m s^-1 // natural unit of mom.um in MeV/c 0.510 998 9461 0.000 000 0031 MeV/c // natural unit of time 1.288 088 667 12 e-21 0.000 000 000 58 e-21 s // natural unit of velocity 299 792 458 (exact) m s^-1 // neutron Compton wavelength 1.319 590 904 81 e-15 0.000 000 000 88 e-15 m // neutron Compton wavelength over 2 pi 0.210 019 415 36 e-15 0.000 000 000 14 e-15 m // neutron-electron mag. mom. ratio 1.040 668 82 e-3 0.000 000 25 e-3 // neutron-electron mass ratio 1838.683 661 58 0.000 000 90 // neutron g factor -3.826 085 45 0.000 000 90 // neutron gyromag. ratio 1.832 471 72 e8 0.000 000 43 e8 s^-1 T^-1 // neutron gyromag. ratio over 2 pi 29.164 6933 0.000 0069 MHz T^-1 // neutron mag. mom. -0.966 236 50 e-26 0.000 000 23 e-26 J T^-1 // neutron mag. mom. to Bohr magneton ratio -1.041 875 63 e-3 0.000 000 25 e-3 // neutron mag. mom. to nuclear magneton ratio -1.913 042 73 0.000 000 45 // neutron mass energy equivalent 1.505 349 739 e-10 0.000 000 019 e-10 J // neutron mass energy equivalent in MeV 939.565 4133 0.000 0058 MeV // neutron mass in u 1.008 664 915 88 0.000 000 000 49 u // neutron molar mass 1.008 664 915 88 e-3 0.000 000 000 49 e-3 kg mol^-1 // neutron-muon mass ratio 8.892 484 08 0.000 000 20 // neutron-proton mag. mom. ratio -0.684 979 34 0.000 000 16 // neutron-proton mass difference 2.305 573 77 e-30 0.000 000 85 e-30 // neutron-proton mass difference energy equivalent 2.072 146 37 e-13 0.000 000 76 e-13 // neutron-proton mass difference energy equivalent in MeV 1.293 332 05 0.000 000 48 // neutron-proton mass difference in u 0.001 388 449 00 0.000 000 000 51 // neutron-proton mass ratio 1.001 378 418 98 0.000 000 000 51 // neutron-tau mass ratio 0.528 790 0.000 048 // neutron to shielded proton mag. mom. ratio -0.684 996 94 0.000 000 16 // Newtonian constant of gravitation over h-bar c 6.708 61 e-39 0.000 31 e-39 (GeV/c^2)^-2 // nuclear magneton in eV/T 3.152 451 2550 e-8 0.000 000 0015 e-8 eV T^-1 // nuclear magneton in inverse meters per tesla 2.542 623 432 e-2 0.000 000 016 e-2 m^-1 T^-1 // nuclear magneton in K/T 3.658 2690 e-4 0.000 0021 e-4 K T^-1 // nuclear magneton in MHz/T 7.622 593 285 0.000 000 047 MHz T^-1 // Planck constant in eV s 4.135 667 662 e-15 0.000 000 025 e-15 eV s // Planck constant over 2 pi in eV s 6.582 119 514 e-16 0.000 000 040 e-16 eV s // Planck constant over 2 pi times c in MeV fm 197.326 9788 0.000 0012 MeV fm // Planck length 1.616 229 e-35 0.000 038 e-35 m // Planck mass 2.176 470 e-8 0.000 051 e-8 kg // Planck mass energy equivalent in GeV 1.220 910 e19 0.000 029 e19 GeV // Planck temperature 1.416 808 e32 0.000 033 e32 K // Planck time 5.391 16 e-44 0.000 13 e-44 s // proton charge to mass quotient 9.578 833 226 e7 0.000 000 059 e7 C kg^-1 // proton Compton wavelength 1.321 409 853 96 e-15 0.000 000 000 61 e-15 m // proton Compton wavelength over 2 pi 0.210 308 910 109 e-15 0.000 000 000 097 e-15 m // proton-electron mass ratio 1836.152 673 89 0.000 000 17 // proton g factor 5.585 694 702 0.000 000 017 // proton gyromag. ratio 2.675 221 900 e8 0.000 000 018 e8 s^-1 T^-1 // proton gyromag. ratio over 2 pi 42.577 478 92 0.000 000 29 MHz T^-1 // proton mag. mom. 1.410 606 7873 e-26 0.000 000 0097 e-26 J T^-1 // proton mag. mom. to Bohr magneton ratio 1.521 032 2053 e-3 0.000 000 0046 e-3 // proton mag. mom. to nuclear magneton ratio 2.792 847 3508 0.000 000 0085 // proton mag. shielding correction 25.691 e-6 0.011 e-6 // proton mass energy equivalent 1.503 277 593 e-10 0.000 000 018 e-10 J // proton mass energy equivalent in MeV 938.272 0813 0.000 0058 MeV // proton mass in u 1.007 276 466 879 0.000 000 000 091 u // proton molar mass 1.007 276 466 879 e-3 0.000 000 000 091 e-3 kg mol^-1 // proton-muon mass ratio 8.880 243 38 0.000 000 20 // proton-neutron mag. mom. ratio -1.459 898 05 0.000 000 34 // proton-neutron mass ratio 0.998 623 478 44 0.000 000 000 51 // proton rms charge radius 0.8751 e-15 0.0061 e-15 m // proton-tau mass ratio 0.528 063 0.000 048 // Rydberg constant times c in Hz 3.289 841 960 355 e15 0.000 000 000 019 e15 Hz // Rydberg constant times hc in eV 13.605 693 009 0.000 000 084 eV // Rydberg constant times hc in J 2.179 872 325 e-18 0.000 000 027 e-18 J // Sackur-Tetrode constant (1 K, 100 kPa) -1.151 7084 0.000 0014 // Sackur-Tetrode constant (1 K, 101.325 kPa) -1.164 8714 0.000 0014 // shielded helion gyromag. ratio 2.037 894 585 e8 0.000 000 027 e8 s^-1 T^-1 // shielded helion gyromag. ratio over 2 pi 32.434 099 66 0.000 000 43 MHz T^-1 // shielded helion mag. mom. -1.074 553 080 e-26 0.000 000 014 e-26 J T^-1 // shielded helion mag. mom. to Bohr magneton ratio -1.158 671 471 e-3 0.000 000 014 e-3 // shielded helion mag. mom. to nuclear magneton ratio -2.127 497 720 0.000 000 025 // shielded helion to proton mag. mom. ratio -0.761 766 5603 0.000 000 0092 // shielded helion to shielded proton mag. mom. ratio -0.761 786 1313 0.000 000 0033 // shielded proton gyromag. ratio 2.675 153 171 e8 0.000 000 033 e8 s^-1 T^-1 // shielded proton gyromag. ratio over 2 pi 42.576 385 07 0.000 000 53 MHz T^-1 // shielded proton mag. mom. 1.410 570 547 e-26 0.000 000 018 e-26 J T^-1 // shielded proton mag. mom. to Bohr magneton ratio 1.520 993 128 e-3 0.000 000 017 e-3 // shielded proton mag. mom. to nuclear magneton ratio 2.792 775 600 0.000 000 030 // standard atmosphere 101 325 (exact) Pa // standard-state pressure 100 000 (exact) Pa // tau Compton wavelength 0.697 787 e-15 0.000 063 e-15 m // tau Compton wavelength over 2 pi 0.111 056 e-15 0.000 010 e-15 m // tau-electron mass ratio 3477.15 0.31 // tau mass energy equivalent 2.846 78 e-10 0.000 26 e-10 J // tau mass in u 1.907 49 0.000 17 u // tau molar mass 1.907 49 e-3 0.000 17 e-3 kg mol^-1 // tau-muon mass ratio 16.8167 0.0015 // tau-neutron mass ratio 1.891 11 0.000 17 // tau-proton mass ratio 1.893 72 0.000 17 // triton-electron mass ratio 5496.921 535 88 0.000 000 26 // triton g factor 5.957 924 920 0.000 000 028 // triton mag. mom. 1.504 609 503 e-26 0.000 000 012 e-26 J T^-1 // triton mag. mom. to Bohr magneton ratio 1.622 393 6616 e-3 0.000 000 0076 e-3 // triton mag. mom. to nuclear magneton ratio 2.978 962 460 0.000 000 014 // triton mass 5.007 356 665 e-27 0.000 000 062 e-27 kg // triton mass energy equivalent 4.500 387 735 e-10 0.000 000 055 e-10 J // triton mass energy equivalent in MeV 2808.921 112 0.000 017 MeV // triton mass in u 3.015 500 716 32 0.000 000 000 11 u // triton molar mass 3.015 500 716 32 e-3 0.000 000 000 11 e-3 kg mol^-1 // triton-proton mass ratio 2.993 717 033 48 0.000 000 000 22 // unified atomic mass unit 1.660 539 040 e-27 0.000 000 020 e-27 kg // Wien frequency displacement law constant 5.878 9238 e10 0.000 0034 e10 Hz K^-1 // Wien wavelength displacement law constant 2.897 7729 e-3 0.000 0017 e-3 m K // Universal. PUSH_CONSTANT_NO_UNIT("π (Archimedes' constant pi)", "3.1415926535897932"); PUSH_CONSTANT_NO_UNIT("e (Euler's number)", "2.7182818284590452"); PUSH_CONSTANT_NO_UNIT("φ (golden ratio)", "1.6180339887498948"); // General Physics. PUSH_CONSTANT_CODATA("Characteristic Impedance of Vacuum", "376.730313461", "Ω", "exact", "2016-03-28"); PUSH_CONSTANT_CODATA("Dirac's Constant", "1.054571800e-34", "J·s", "0.000000013e-34", "2016-03-28"); // CODATA name: Planck constant over 2 pi PUSH_CONSTANT_CODATA("Electric Constant", "8.854187817e-12", "F/m", "exact", "2016-03-28"); PUSH_CONSTANT_CODATA("Gravitation Constant", "6.67408e-11", "m³/(kg·s²)", "0.00031e-11", "2016-03-28"); PUSH_CONSTANT_CODATA("Magnetic Constant", "12.566370614e-7", "N/A²", "exact", "2016-03-28"); // TODO: Put more figures ! PUSH_CONSTANT_CODATA("Planck's Constant", "6.626070040e-34", "J·s", "0.000000081e-34", "2016-03-28"); PUSH_CONSTANT_CODATA("Speed of Light in Vacuum", "299792458", "m/s", "exact", "2016-03-28"); PUSH_CONSTANT_CODATA("Standard Gravity", "9.80665", "m/s²", "exact", "2016-03-28"); // Electromagnetic. PUSH_CONSTANT_CODATA("Bohr-Procopiu Magneton", "927.4009994e-26", "J/T", "0.0000057e-26", "2016-03-28"); PUSH_CONSTANT_CODATA("Conductance Quantum", "7.7480917310e-5", "S", "0.0000000018e-5", "2016-03-28"); PUSH_CONSTANT("Coulomb's Constant", "8.987742438e9", "N·m²/C²"); PUSH_CONSTANT_CODATA("Elementary Charge", "1.602 176 6208 e-19", "C", "0.0000000098e-19", "2016-03-28"); PUSH_CONSTANT_CODATA("Conventional value of Josephson Constant", "483597.9e9", "Hz/V", "exact", "2016-03-28"); PUSH_CONSTANT_CODATA("Josephson Constant", "483597.8525e9", "Hz/V", "0.0030e9", "2016-03-28"); PUSH_CONSTANT_CODATA("Magnetic Flux Quantum", "2.06783383e-15", "Wb", "0.000000013e-15", "2016-03-28"); PUSH_CONSTANT_CODATA("Nuclear Magneton", "5.050783699e-27", "J/T", "0.000000031e-27", "2016-03-28"); PUSH_CONSTANT_CODATA("Resistance Quantum", "12906.4037278", "Ω", "0.0000029", "2016-03-28"); // CODATA name: inverse of conductance quantum PUSH_CONSTANT_CODATA("Conventional value of von Klitzing Constant", "25812.807", "Ω", "exact", "2016-03-28"); PUSH_CONSTANT_CODATA("von Klitzing Constant", "25812.8074555", "Ω", "0.0000059", "2016-03-28"); // Atomic & Nuclear. PUSH_CONSTANT_CODATA("Bohr Radius", "0.52917721067e-10", "m", "0.00000000012e-10", "2016-03-28"); PUSH_CONSTANT_CODATA("Fermi Coupling Constant", "1.1663787e-5", "Ge/V²", "0.0000006e-5", "2016-03-28"); PUSH_CONSTANT_CODATA("Fine-structure Constant", "7.2973525664e-3", "", "0.0000000017e-3", "2016-03-28"); PUSH_CONSTANT_CODATA("Hartree Energy", "4.359744650e-18", "J", "0.000000054e-18", "2016-03-28"); PUSH_CONSTANT_CODATA("Hartree Energy in eV", "27.21138602", "ev", "0.00000017", "2016-03-28"); PUSH_CONSTANT_CODATA("Quantum of Circulation", "3.6369475486e-4", "m²/s", "0.0000000017e-4", "2016-03-28"); PUSH_CONSTANT_CODATA("Quantum of Circulation times 2", "7.2738950972e-4", "m²/s", "0.0000000033e-4", "2016-03-28"); // I don't know why it is useful, but it is present in CODATA constants, so I added it -- Hadrien Theveneau, 2016-03-28 PUSH_CONSTANT_CODATA("Rydberg Constant", "10973731.568508", "1/m", "0.000065", "2016-03-28"); PUSH_CONSTANT_CODATA("Thomson Cross Section", "0.66524587158e-28", "m²", "0.00000000091e-28", "2016-03-28"); PUSH_CONSTANT_CODATA("Weak Mixing Angle", "0.2223", "", "0.0021", "2016-03-28"); // Physico-chemical. PUSH_CONSTANT_CODATA("Atomic Mass Unit", "1.660539040e-27", "kg", "0.000000020e-27", "2016-03-28"); // CODATA name: atomic mass constant PUSH_CONSTANT_CODATA("Avogadro's Number", "6.022140857e23", "1/mol", "0.000000074e23", "2016-03-28"); // CODATA name: Avogadro constant PUSH_CONSTANT_CODATA("Boltzmann Constant", "1.38064852e-23", "J/K", "0.00000079e-23", "2016-03-28"); PUSH_CONSTANT_CODATA("Compton wavelength", "2.4263102367e-12", "m", "0.0000000011e-12", "2016-03-28"); PUSH_CONSTANT_CODATA("Compton wavelength over 2 pi", "386.15926764e-15", "m", "0.00000018e-15", "2016-03-28"); PUSH_CONSTANT_CODATA("Electron-volt", "1.6021766208e-19", "J", "0.0000000098e-19", "2016-03-28"); PUSH_CONSTANT_CODATA("Faraday Constant", "96485.33289", "C/mol", "0.00059", "2016-03-28"); // PUSH_CONSTANT_CODATA("Faraday constant for conventional electric current", "96 485.3251", "C_90_mol^-1", "0.0012", "2016-03-28"); // TODO: Handle C_90_mol PUSH_CONSTANT_CODATA("First Radiation Constant", "3.741771790e-16", "W·m²", "0.000000046e-16", "2016-03-28"); PUSH_CONSTANT_CODATA("First Radiation Constant for Spectral Radiance", "1.191042953e-16", "(W·m²)/sr", "0.000000015e-16", "2016-03-28"); PUSH_CONSTANT_CODATA("Gas Constant", "8.3144598", "J/(K·mol)", "0.0000048", "2016-03-28"); PUSH_CONSTANT_CODATA("Loschmidt constant (273.15 K, 100 kPa)", "2.6516467e25", "1/m³", "0.0000015e25", "2016-03-28"); PUSH_CONSTANT_CODATA("Loschmidt constant (273.15 K, 101.325 kPa)", "2.6867811e25", "1/m³", "0.0000015e25", "2016-03-28"); PUSH_CONSTANT_CODATA("Molar Planck Constant", "3.9903127110e-10", "J·s/mol", "0.0000000018e-10", "2016-03-28"); PUSH_CONSTANT_CODATA("Second Radiation Constant", "1.43877736e-2", "m·K", "0.00000083e-2", "2016-03-28"); PUSH_CONSTANT_CODATA("Stefan-Boltzmann Constant", "5.670367e-8", "W/(m²·K⁴)", "0.000013e-8", "2016-03-28"); PUSH_CONSTANT_CODATA("{220} Lattice Spacing of Silicon", "192.0155714e-12", "kg", "0.0000032e-12", "2016-03-28"); // Astronomy. PUSH_CONSTANT("Astronomical Unit", "149597870691", "m"); PUSH_CONSTANT("Light Year", "9.4607304725808e15", "m"); PUSH_CONSTANT("Parsec", "3.08567802e16", "m"); PUSH_CONSTANT_NO_UNIT("Gregorian Year", "365.2425"); PUSH_CONSTANT_NO_UNIT("Julian Year", "365.25"); PUSH_CONSTANT_NO_UNIT("Sidereal Year", "365.2564"); PUSH_CONSTANT_NO_UNIT("Tropical Year", "365.2422"); PUSH_CONSTANT("Earth Mass", "5.9736e24", "kg"); PUSH_CONSTANT("Mean Earth Radius", "6371000", "m"); PUSH_CONSTANT("Sun Mass", "1.9891e30", "kg"); PUSH_CONSTANT("Sun Radius", "6.96265e8", "m"); PUSH_CONSTANT("Sun Luminosity", "3.827e26", "W"); // Molar Masses PUSH_CONSTANT("Aluminium", "26.9815386", "g/mol"); PUSH_CONSTANT("Antimony", "121.760", "g/mol"); PUSH_CONSTANT("Argon", "39.948", "g/mol"); PUSH_CONSTANT("Arsenic", "74.92160", "g/mol"); PUSH_CONSTANT("Barium", "137.327", "g/mol"); PUSH_CONSTANT("Beryllium", "9.012182", "g/mol"); PUSH_CONSTANT("Bismuth", "208.98040", "g/mol"); PUSH_CONSTANT("Boron", "10.811", "g/mol"); PUSH_CONSTANT("Bromine", "79.904", "g/mol"); PUSH_CONSTANT("Cadmium", "112.411", "g/mol"); PUSH_CONSTANT("Caesium", "132.9054519", "g/mol"); PUSH_CONSTANT("Calcium", "40.078", "g/mol"); PUSH_CONSTANT("Carbon", "12.0107", "g/mol"); PUSH_CONSTANT("Cerium", "140.116", "g/mol"); PUSH_CONSTANT("Chlorine", "35.453", "g/mol"); PUSH_CONSTANT("Chromium", "51.9961", "g/mol"); PUSH_CONSTANT("Cobalt", "58.933195", "g/mol"); PUSH_CONSTANT("Copper", "63.546", "g/mol"); PUSH_CONSTANT("Dysprosium", "162.500", "g/mol"); PUSH_CONSTANT("Erbium", "167.259", "g/mol"); PUSH_CONSTANT("Europium", "151.964", "g/mol"); PUSH_CONSTANT("Fluorine", "18.9984032", "g/mol"); PUSH_CONSTANT("Gadolinium", "157.25", "g/mol"); PUSH_CONSTANT("Gallium", "69.723", "g/mol"); PUSH_CONSTANT("Germanium", "72.64", "g/mol"); PUSH_CONSTANT("Gold", "196.966569", "g/mol"); PUSH_CONSTANT("Hafnium", "178.49", "g/mol"); PUSH_CONSTANT("Helium", "4.002602", "g/mol"); PUSH_CONSTANT("Holmium", "164.93032", "g/mol"); PUSH_CONSTANT("Hydrogen", "1.00794", "g/mol"); PUSH_CONSTANT("Indium", "114.818", "g/mol"); PUSH_CONSTANT("Iodine", "126.90447", "g/mol"); PUSH_CONSTANT("Iridium", "192.217", "g/mol"); PUSH_CONSTANT("Iron", "55.845", "g/mol"); PUSH_CONSTANT("Krypton", "83.798", "g/mol"); PUSH_CONSTANT("Lanthanum", "138.90547", "g/mol"); PUSH_CONSTANT("Lead", "207.2", "g/mol"); PUSH_CONSTANT("Lithium", "6.941", "g/mol"); PUSH_CONSTANT("Lutetium", "174.9668", "g/mol"); PUSH_CONSTANT("Magnesium", "24.3050", "g/mol"); PUSH_CONSTANT("Manganese", "54.938045", "g/mol"); PUSH_CONSTANT("Mercury", "200.59", "g/mol"); PUSH_CONSTANT("Molybdenum", "95.96", "g/mol"); PUSH_CONSTANT("Neodymium", "144.242", "g/mol"); PUSH_CONSTANT("Neon", "20.1797", "g/mol"); PUSH_CONSTANT("Nickel", "58.6934", "g/mol"); PUSH_CONSTANT("Niobium", "92.90638", "g/mol"); PUSH_CONSTANT("Nitrogen", "14.0067", "g/mol"); PUSH_CONSTANT("Osmium", "190.23", "g/mol"); PUSH_CONSTANT("Oxygen", "15.9994", "g/mol"); PUSH_CONSTANT("Palladium", "106.42", "g/mol"); PUSH_CONSTANT("Phosphorus", "30.973762", "g/mol"); PUSH_CONSTANT("Platinum", "192.084", "g/mol"); PUSH_CONSTANT("Potassium", "39.0983", "g/mol"); PUSH_CONSTANT("Praseodymium", "140.90765", "g/mol"); PUSH_CONSTANT("Protactinium", "231.03588", "g/mol"); PUSH_CONSTANT("Rhenium", "186.207", "g/mol"); PUSH_CONSTANT("Rubidium", "85.4678", "g/mol"); PUSH_CONSTANT("Ruthenium", "101.07", "g/mol"); PUSH_CONSTANT("Samarium", "150.36", "g/mol"); PUSH_CONSTANT("Scandium", "44.955912", "g/mol"); PUSH_CONSTANT("Selenium", "78.96", "g/mol"); PUSH_CONSTANT("Silicon", "28.0855", "g/mol"); PUSH_CONSTANT("Silver", "107.8682", "g/mol"); PUSH_CONSTANT("Sodium", "22.98976928", "g/mol"); PUSH_CONSTANT("Strontium", "87.62", "g/mol"); PUSH_CONSTANT("Sulfur", "32.065", "g/mol"); PUSH_CONSTANT("Tantalum", "180.94788", "g/mol"); PUSH_CONSTANT("Tellurium", "127.60", "g/mol"); PUSH_CONSTANT("Terbium", "158.92535", "g/mol"); PUSH_CONSTANT("Thallium", "204.3833", "g/mol"); PUSH_CONSTANT("Thorium", "232.03806", "g/mol"); PUSH_CONSTANT("Thulium", "168.93421", "g/mol"); PUSH_CONSTANT("Tin", "118.710", "g/mol"); PUSH_CONSTANT("Titanium", "47.867", "g/mol"); PUSH_CONSTANT("Tungsten", "183.84", "g/mol"); PUSH_CONSTANT("Uranium", "238.02891", "g/mol"); PUSH_CONSTANT("Vanadium", "51.9961", "g/mol"); PUSH_CONSTANT("Xenon", "131.293", "g/mol"); PUSH_CONSTANT("Ytterbium", "173.054", "g/mol"); PUSH_CONSTANT("Yttrium", "88.90585", "g/mol"); PUSH_CONSTANT("Zinc", "65.38", "g/mol"); PUSH_CONSTANT("Zirconium", "91.224", "g/mol"); // Particle Masses // Leptons PUSH_CONSTANT_CODATA("Electron Mass", "0.5109989461", "MeV/c²", "0.0000000031", "2016-03-28"); PUSH_CONSTANT_CODATA("Muon Mass", "105.6583745", "MeV/c²", "0.0000024", "2016-03-28"); PUSH_CONSTANT_CODATA("Tau Mass", "1776.82", "MeV/c²", "0.16", "2016-03-28"); // Quarks PUSH_CONSTANT("Up-Quark Mass", "2.3", "MeV/c²"); PUSH_CONSTANT("Down-Quark Mass", "4.8", "MeV/c²"); PUSH_CONSTANT("Charm-Quark Mass", "1.275", "GeV/c²"); PUSH_CONSTANT("Strange-Quark Mass", "95", "MeV/c²"); PUSH_CONSTANT("Top-Quark Mass", "173.21", "GeV/c²"); PUSH_CONSTANT("Bottom-Quark Mass", "4.18", "GeV/c²"); // Bosons PUSH_CONSTANT("W-Boson Mass", "80.385" , "GeV/c²"); PUSH_CONSTANT("Z-Boson Mass", "91.1876", "GeV/c²"); PUSH_CONSTANT("Higgs-Boson Mass", "125.7", "GeV/c²"); // Hadrons PUSH_CONSTANT_CODATA("Proton Mass", "938.2720813", "MeV/c²", "0.0000058", "2016-03-28"); PUSH_CONSTANT_CODATA("Neutron Mass", "939.5654133", "MeV/c²", "0.0000058", "2016-03-28"); // SI-Units PUSH_CONSTANT_CODATA("Electron Mass (SI)", "9.10938356e-31", "kg", "0.00000011e-31", "2016-03-28"); PUSH_CONSTANT_CODATA("Proton Mass (SI)", "1.672621898e-27", "kg", "0.000000021e-27", "2016-03-28"); PUSH_CONSTANT_CODATA("Neutron Mass (SI)", "1.674927471e-27", "kg", "0.000000021e-27", "2016-03-28"); } void Constants::Private::retranslateText() { auto i = list.begin(); QString cat; // http://en.wikipedia.org/wiki/Mathematical_constant cat = QString("Universal"); I18N_CONSTANT(QString("Archimedes' constant Pi") + QString::fromUtf8(" (π)")); I18N_CONSTANT(QString("Euler's number") + QString::fromUtf8(" (ℯ)")); I18N_CONSTANT(QString("Golden ratio") + QString::fromUtf8(" (φ)")); // http://en.wikipedia.org/wiki/Physical_constant#Table_of_universal_constants cat = QString("General Physics"); I18N_CONSTANT(QString("Characteristic Impedance of Vacuum")); I18N_CONSTANT(QString("Dirac's Constant")); I18N_CONSTANT(QString("Electric Constant")); I18N_CONSTANT(QString("Gravitation Constant")); I18N_CONSTANT(QString("Magnetic Constant")); I18N_CONSTANT(QString("Planck's Constant")); I18N_CONSTANT(QString("Speed of Light in Vacuum")); I18N_CONSTANT(QString("Standard Gravity")); // http://en.wikipedia.org/wiki/Physical_constant#Table_of_electromagnetic_constants cat = QString("Electromagnetic"); I18N_CONSTANT(QString("Bohr-Procopiu Magneton")); I18N_CONSTANT(QString("Conductance Quantum")); I18N_CONSTANT(QString("Coulomb's Constant")); I18N_CONSTANT(QString("Elementary Charge")); I18N_CONSTANT(QString("Conventional value of Josephson Constant")); I18N_CONSTANT(QString("Josephson Constant")); I18N_CONSTANT(QString("Magnetic Flux Quantum")); I18N_CONSTANT(QString("Nuclear Magneton")); I18N_CONSTANT(QString("Resistance Quantum")); I18N_CONSTANT(QString("Conventional value of von Klitzing Constant")); I18N_CONSTANT(QString("von Klitzing Constant")); // CODATA cat = QString("Atomic & Nuclear"); I18N_CONSTANT(QString("Bohr Radius")); I18N_CONSTANT(QString("Fermi Coupling Constant")); I18N_CONSTANT(QString("Fine-structure Constant")); I18N_CONSTANT(QString("Hartree Energy")); I18N_CONSTANT(QString("Hartree Energy in eV")); I18N_CONSTANT(QString("Quantum of Circulation")); I18N_CONSTANT(QString("Quantum of Circulation times 2")); I18N_CONSTANT(QString("Rydberg Constant")); I18N_CONSTANT(QString("Thomson Cross Section")); I18N_CONSTANT(QString("Weak Mixing Angle")); // CODATA cat = QString("Physico-chemical"); I18N_CONSTANT(QString("Atomic Mass Unit")); I18N_CONSTANT(QString("Avogadro's Number")); I18N_CONSTANT(QString("Boltzmann Constant")); I18N_CONSTANT(QString("Compton wavelength")); I18N_CONSTANT(QString("Compton wavelength over 2 pi")); I18N_CONSTANT(QString("Electron volt")); I18N_CONSTANT(QString("Faraday Constant")); I18N_CONSTANT(QString("First Radiation Constant")); I18N_CONSTANT(QString("First Radiation Constant for Spectral Radiance")); I18N_CONSTANT(QString("Gas Constant")); I18N_CONSTANT(QString("Loschmidt constant (273.15 K, 100 kPa)")); I18N_CONSTANT(QString("Loschmidt constant (273.15 K, 101.325 kPa)")); I18N_CONSTANT(QString("Molar Planck Constant")); I18N_CONSTANT(QString("Second Radiation Constant")); I18N_CONSTANT(QString("Stefan-Boltzmann Constant")); I18N_CONSTANT(QString("{220} Lattice Spacing of Silicon")); // http://www.astronomynotes.com/tables/tablesa.htm cat = QString("Astronomy"); I18N_CONSTANT(QString("Astronomical Unit")); I18N_CONSTANT(QString("Light Year")); I18N_CONSTANT(QString("Parsec")); const QString days = QString("days"); I18N_CONSTANT_DAYS(QString("Gregorian Year")); I18N_CONSTANT_DAYS(QString("Julian Year")); I18N_CONSTANT_DAYS(QString("Sidereal Year")); I18N_CONSTANT_DAYS(QString("Tropical Year")); I18N_CONSTANT(QString("Earth Mass")); I18N_CONSTANT(QString("Mean Earth Radius")); I18N_CONSTANT(QString("Sun Mass")); I18N_CONSTANT(QString("Sun Radius")); I18N_CONSTANT(QString("Sun Luminosity")); // http://www.ptable.com/ // Only known constants of accuracy more than an integer are included. cat = QString("Molar Mass"); I18N_CONSTANT(QString("Aluminium")); I18N_CONSTANT(QString("Antimony")); I18N_CONSTANT(QString("Argon")); I18N_CONSTANT(QString("Arsenic")); I18N_CONSTANT(QString("Barium")); I18N_CONSTANT(QString("Beryllium")); I18N_CONSTANT(QString("Bismuth")); I18N_CONSTANT(QString("Boron")); I18N_CONSTANT(QString("Bromine")); I18N_CONSTANT(QString("Cadmium")); I18N_CONSTANT(QString("Caesium")); I18N_CONSTANT(QString("Calcium")); I18N_CONSTANT(QString("Carbon")); I18N_CONSTANT(QString("Cerium")); I18N_CONSTANT(QString("Chlorine")); I18N_CONSTANT(QString("Chromium")); I18N_CONSTANT(QString("Cobalt")); I18N_CONSTANT(QString("Copper")); I18N_CONSTANT(QString("Dysprosium")); I18N_CONSTANT(QString("Erbium")); I18N_CONSTANT(QString("Europium")); I18N_CONSTANT(QString("Fluorine")); I18N_CONSTANT(QString("Gadolinium")); I18N_CONSTANT(QString("Gallium")); I18N_CONSTANT(QString("Germanium")); I18N_CONSTANT(QString("Gold")); I18N_CONSTANT(QString("Hafnium")); I18N_CONSTANT(QString("Helium")); I18N_CONSTANT(QString("Holmium")); I18N_CONSTANT(QString("Hydrogen")); I18N_CONSTANT(QString("Indium")); I18N_CONSTANT(QString("Iodine")); I18N_CONSTANT(QString("Iridium")); I18N_CONSTANT(QString("Iron")); I18N_CONSTANT(QString("Krypton")); I18N_CONSTANT(QString("Lanthanum")); I18N_CONSTANT(QString("Lead")); I18N_CONSTANT(QString("Lithium")); I18N_CONSTANT(QString("Lutetium")); I18N_CONSTANT(QString("Magnesium")); I18N_CONSTANT(QString("Manganese")); I18N_CONSTANT(QString("Mercury")); I18N_CONSTANT(QString("Molybdenum")); I18N_CONSTANT(QString("Neodymium")); I18N_CONSTANT(QString("Neon")); I18N_CONSTANT(QString("Nickel")); I18N_CONSTANT(QString("Niobium")); I18N_CONSTANT(QString("Nitrogen")); I18N_CONSTANT(QString("Osmium")); I18N_CONSTANT(QString("Oxygen")); I18N_CONSTANT(QString("Palladium")); I18N_CONSTANT(QString("Phosphorus")); I18N_CONSTANT(QString("Platinum")); I18N_CONSTANT(QString("Potassium")); I18N_CONSTANT(QString("Praseodymium")); I18N_CONSTANT(QString("Protactinium")); I18N_CONSTANT(QString("Rhenium")); I18N_CONSTANT(QString("Rubidium")); I18N_CONSTANT(QString("Ruthenium")); I18N_CONSTANT(QString("Samarium")); I18N_CONSTANT(QString("Scandium")); I18N_CONSTANT(QString("Selenium")); I18N_CONSTANT(QString("Silicon")); I18N_CONSTANT(QString("Silver")); I18N_CONSTANT(QString("Sodium")); I18N_CONSTANT(QString("Strontium")); I18N_CONSTANT(QString("Sulfur")); I18N_CONSTANT(QString("Tantalum")); I18N_CONSTANT(QString("Tellurium")); I18N_CONSTANT(QString("Terbium")); I18N_CONSTANT(QString("Thallium")); I18N_CONSTANT(QString("Thorium")); I18N_CONSTANT(QString("Thulium")); I18N_CONSTANT(QString("Tin")); I18N_CONSTANT(QString("Titanium")); I18N_CONSTANT(QString("Tungsten")); I18N_CONSTANT(QString("Uranium")); I18N_CONSTANT(QString("Vanadium")); I18N_CONSTANT(QString("Xenon")); I18N_CONSTANT(QString("Ytterbium")); I18N_CONSTANT(QString("Yttrium")); I18N_CONSTANT(QString("Zinc")); I18N_CONSTANT(QString("Zirconium")); // K.A. Olive et al. (Particle Data Group), Chin. Phys. C, 38, 090001 (2014). // http://pdg.lbl.gov/index.html // CODATA constants cat = QString("Particle Masses"); I18N_CONSTANT(QString("Electron Mass")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Muon Mass")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Tau Mass")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Up-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("Down-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("Charm-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("Strange-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("Top-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("Bottom-Quark Mass")); // Particle Data Group I18N_CONSTANT(QString("W-Boson Mass")); // Particle Data Group I18N_CONSTANT(QString("Z-Boson Mass")); // Particle Data Group I18N_CONSTANT(QString("Higgs-Boson Mass")); // Particle Data Group I18N_CONSTANT(QString("Proton Mass")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Neutron Mass")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Electron Mass (SI)")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Proton Mass (SI)")); // CODATA, 2016-03-28 I18N_CONSTANT(QString("Neutron Mass (SI)")); // CODATA, 2016-03-28 categories.clear(); for (int k = 0; k < list.count(); ++k) if (!categories.contains(list.at(k).category)) categories += list.at(k).category; categories.sort(); } Constants* Constants::instance() { if (!s_constantsInstance) { s_constantsInstance = new Constants; qAddPostRoutine(s_deleteConstants); } return s_constantsInstance; } Constants::Constants() : d(new Constants::Private) { setObjectName("Constants"); d->populate(); d->retranslateText(); } const QList& Constants::list() const { return d->list; } const QStringList& Constants::categories() const { return d->categories; } void Constants::retranslateText() { d->retranslateText(); } Constants::~Constants() { } deepin-calculator-1.0.2/core/constants.h000066400000000000000000000030611325241207700202250ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2007 Ariya Hidayat // Copyright (C) 2008-2009, 2016 @heldercorreia // Copyright (C) 2009 Andreas Scherer // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_CONSTANTS_H #define CORE_CONSTANTS_H #include #include #include struct Constant { QString category; QString name; QString unit; QString value; }; class Constants : public QObject { Q_OBJECT public: ~Constants(); // For unique_ptr, define after Private is complete. static Constants* instance(); const QStringList& categories() const; const QList& list() const; public slots: void retranslateText(); private: struct Private; std::unique_ptr d; Constants(); Q_DISABLE_COPY(Constants) }; #endif deepin-calculator-1.0.2/core/errors.h000066400000000000000000000115621325241207700175320ustar00rootroot00000000000000/* errors.h global list of error codes Copyright (C) 2007, 2008 Wolf Lammen ookami1 gmx de 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 2 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ERRORS_H #define _ERRORS_H #ifdef __cplusplus extern "C"{ #endif typedef enum { Success = 0, /* a NaN or an empty Variant was submitted as a parameter. Only a few functions in the math engine accept such a value. All arithmetic functions fail on such an operand */ NoOperand, /* This error is returned if a result is mathematically defined, but cannot be computed reliably without extending the working precision considerably and/or requiring considerable computing time */ EvalUnstable, /* the result is in absolute value smaller than the smallest non-zero value the math engine can handle */ Underflow, /* the result is in absolute value bigger than the biggest number the math engine can handle */ Overflow, /* operation requests a division by zero, or a function was evaluated at a pole */ ZeroDivide, /* One or more parameters to a function lie outside of the function's domain */ OutOfDomain, /* a number exceeds the logic number range, so logic operations cannot be applied */ OutOfLogicRange, /* a number or a result exceeds the integer range */ OutOfIntegerRange, /* This error indicates a failed conversion from an ASCII string. Functions setting this error may also report a more detailed IO... error code*/ BadLiteral, /* A request to calculate something to more places than is (currently) acceptable */ InvalidPrecision, /* A parameter violates the limitations of the engine, or is completely meaningless, e.g. the evaluation of a quotient and a remainder in the same variable. This error indicates a bug, because the calling program should never submit such a parameter (combinations) */ InvalidParam, /* returned when an operation request is mathematically valid, but would require too much time */ TooExpensive, /* For correct conversion of a digit sequence, the IO routines need information about the radix to use. This error is returned if none was specified. This error indicates a bug, because a calling routine should always supply this information */ IONoBase, /* This error occurs if you request a two's complement conversion, and either additionally specify a sign, or gave a non-zero fraction */ IOInvalidComplement, /* You must specify at least one digit of the significant */ IONoSignificand, /* invalid characters in exponent, e.g. a decimal dot */ IOBadExp, /* the exponent exceeds the allowed range */ IOExpOverflow, /* internal (string) buffer overflow in a conversion. This indicates a bug because range checking should be done in advance */ IOBufferOverflow, /* request to convert more digits to another base than internal buffers can hold. This occurs when you try to convert huge values in fixpoint format */ IOConversionOverflow, /* request to convert a tiny number in fixpoint format, so that only leading zeros are displayed. */ IOConversionUnderflow, /* a function was called with the wrong count of parameters e.g. sin(12;13) (sin takes only 1 parameter) */ InvalidParamCount, /* parameter type mismatch */ TypeMismatch, /* occurs if quantities of different dimensions are compared, added, converted, etc. */ DimensionMismatch, /* occurs if a non dimensionless quantity is fed to a function that requires dimensoinless arguments, or if an invalid unit is specified */ InvalidDimension, /* cannot overwrite an existing key in a table */ // KeyExists, /* could not retrieve a symbol by the submitted key */ // SymbolNotFound, /* no matching close token for an open token */ // CloseSymbolMissing, /* unable to clone a symbol, most probably because it was of a special type, like a close parenthesis */ // SymbolCloneError, /* unable to perform a requested type cast */ // BadCast, /* used with variants, when an operation is not implemented for a particular data type. used with formats to indicate a not implemented property */ NotImplemented, /* this value is used internally to indicate the absence of any error information altogether */ NotAnError, /* */ } Error; #ifdef __cplusplus } #endif #endif /* _ERRORS_H */ deepin-calculator-1.0.2/core/evaluator.cpp000066400000000000000000002104471325241207700205560ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2005, 2006 Johan Thelin // Copyright (C) 2007, 2008, 2009, 2010, 2013 @heldercorreia // Copyright (C) 2009 Wolf Lammen // Copyright (C) 2014 Tey // Copyright (C) 2015 Pol Welter // Copyright (C) 2015 Hadrien Theveneau // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "core/evaluator.h" #include "core/session.h" #include "core/settings.h" #include "math/rational.h" #include "math/units.h" #include #include #include #define ALLOW_IMPLICIT_MULT #define MAX_PRECEDENCE INT_MAX #define INVALID_PRECEDENCE INT_MIN static Evaluator* s_evaluatorInstance = 0; static void s_deleteEvaluator() { delete s_evaluatorInstance; } const Quantity& Evaluator::checkOperatorResult(const Quantity& n) { switch (n.error()) { case Success: break; case NoOperand: if(m_assignFunc == false) // the arguments are still NaN, so ignore this error m_error = QString("cannot operate on a NaN"); break; case Underflow: m_error = QString("underflow - tiny result is out of SpeedCrunch's number range"); break; case Overflow: m_error = QString("overflow - huge result is out of SpeedCrunch's number range"); break; case ZeroDivide: m_error = QString("division by zero"); break; case OutOfLogicRange: m_error = QString("overflow - logic result exceeds maximum of 256 bits"); break; case OutOfIntegerRange: m_error = QString("overflow - integer result exceeds maximum limit for integers"); break; case TooExpensive: m_error = QString("too time consuming - computation was rejected"); break; case DimensionMismatch: // we cannot make any assumptions about the dimension of the arguments, so ignore this error when assigning a function if (m_assignFunc == false) m_error = QString("dimension mismatch - quantities with different dimensions cannot be compared, added, etc."); break; case InvalidDimension: m_error = QString("invalid dimension - operation might require dimensionless arguments"); break; case EvalUnstable: m_error = QString("Computation aborted - encountered numerical instability"); break; default:; } return n; } QString Evaluator::stringFromFunctionError(Function* function) { if (!function->error()) return QString(); QString result = QString::fromLatin1("%1: "); switch (function->error()) { case Success: break; case InvalidParamCount: result += QString("wrong number of arguments"); break; case NoOperand: result += QString("does not take NaN as an argument"); break; case Overflow: result += QString("overflow - huge result is out of SpeedCrunch's number range"); break; case Underflow: result += QString("underflow - tiny result is out of SpeedCrunch's number range"); break; case OutOfLogicRange: result += QString("overflow - logic result exceeds maximum of 256 bits"); break; case OutOfIntegerRange: result += QString("result out of range"); break; case ZeroDivide: result += QString("division by zero"); break; case EvalUnstable: result += QString("Computation aborted - encountered numerical instability"); break; case OutOfDomain: result += QString("undefined for argument domain"); break; case TooExpensive: result += QString("computation too expensive"); break; case InvalidDimension: result += QString("invalid dimension - function might require dimensionless arguments"); break; case DimensionMismatch: result += QString("dimension mismatch - quantities with different dimensions cannot be compared, added, etc."); break; case IONoBase: case BadLiteral: case InvalidPrecision: case InvalidParam: result += QString("internal error, please report a bug"); break; default: result += QString("error"); break; }; return result.arg(function->identifier()); } class TokenStack : public QVector { public: TokenStack(); bool isEmpty() const; unsigned itemCount() const; Token pop(); void push(const Token& token); const Token& top(); const Token& top(unsigned index); bool hasError() const { return !m_error.isEmpty(); } QString error() const { return m_error; } void reduce(int count, int minPrecedence = INVALID_PRECEDENCE); void reduce(int count, Token&& top, int minPrecedence = INVALID_PRECEDENCE); void reduce(QList tokens, Token&& top, int minPrecedence = INVALID_PRECEDENCE); private: void ensureSpace(); int topIndex; QString m_error; }; const Token Token::null; // Helper function: return operator of given token text e.g. "*" yields Operator::Asterisk. static Token::Op matchOperator(const QString& text) { Token::Op result = Token::InvalidOp; if (text.length() == 1) { QChar p = text.at(0); switch(p.unicode()) { case '%': result = Token::Percent; break; case '+': result = Token::Plus; break; case '-': result = Token::Minus; break; case '*': result = Token::Asterisk; break; case '/': result = Token::Slash; break; case '^': result = Token::Caret; break; case ';': result = Token::Semicolon; break; case '(': result = Token::LeftPar; break; case ')': result = Token::RightPar; break; case '!': result = Token::Exclamation; break; case '=': result = Token::Equal; break; case '\\': result = Token::Backslash; break; case '&': result = Token::Ampersand; break; case '|': result = Token::Pipe; break; default: result = Token::InvalidOp; } } // else if (text.length() == 2) { // if (text == "**") // result = Token::Caret; // else if(text == "<<") // result = Token::LeftShift; // else if(text == ">>") // result = Token::RightShift; // else if(text == "->") // result = Token::RightArrow; // else if(text == "in") // result = Token::RightArrow; // } return result; } // Helper function: give operator precedence e.g. "+" is 300 while "*" is 500. static int opPrecedence(Token::Op op) { int prec; switch(op) { case Token::Exclamation: prec = 800; break; case Token::Caret: prec = 700; break; case Token::Percent: prec = 800; break; // Not really an operator but needed for managing shift/reduce conflicts. case Token::Function: prec = 600; break; case Token::Asterisk: case Token::Slash: prec = 500; break; case Token::Modulo: case Token::Backslash: prec = 600; break; case Token::Plus: case Token::Minus: prec = 300; break; case Token::LeftShift: case Token::RightShift: prec = 200; break; case Token::Ampersand: prec = 100; break; case Token::Pipe: prec = 50; break; case Token::RightArrow: prec = 0; case Token::RightPar: case Token::Semicolon: prec = -100; break; case Token::LeftPar: prec = -200; break; default: prec = -200; break; } return prec; } Token::Token(Type type, const QString& text, int pos, int size) { m_type = type; m_text = text; m_pos = pos; m_size = size; m_minPrecedence = MAX_PRECEDENCE; } Token::Token(const Token& token) { m_type = token.m_type; m_text = token.m_text; m_pos = token.m_pos; m_size = token.m_size; m_minPrecedence = token.m_minPrecedence; } Token& Token::operator=(const Token& token) { m_type = token.m_type; m_text = token.m_text; m_pos = token.m_pos; m_size = token.m_size; m_minPrecedence = token.m_minPrecedence; return*this; } Quantity Token::asNumber() const { QString text = m_text; return isNumber() ? Quantity(CNumber((const char*)text.toLatin1())) : Quantity(0); } Token::Op Token::asOperator() const { return isOperator() ? matchOperator(m_text) : InvalidOp; } QString Token::description() const { QString desc; switch (m_type) { case stxNumber: desc = "Number"; break; case stxIdentifier: desc = "Identifier"; break; case stxOpenPar: case stxClosePar: case stxSep: case stxOperator: desc = "Operator"; break; default: desc = "Unknown"; break; } while (desc.length() < 10) desc.prepend(' '); QString header; header.append(QString::number(m_pos) + "," + QString::number(m_pos + m_size - 1)); header.append("," + (m_minPrecedence == MAX_PRECEDENCE ? "MAX" : QString::number(m_minPrecedence))); header.append(" "); while (header.length() < 10) header.append(' '); desc.prepend(header); desc.append(" : ").append(m_text); return desc; } static bool tokenPositionCompare(const Token& a, const Token& b) { return (a.pos() < b.pos()); } TokenStack::TokenStack() : QVector() { topIndex = 0; m_error = ""; ensureSpace(); } bool TokenStack::isEmpty() const { return topIndex == 0; } unsigned TokenStack::itemCount() const { return topIndex; } void TokenStack::push(const Token& token) { ensureSpace(); (*this)[topIndex++] = token; } Token TokenStack::pop() { if (topIndex > 0) return Token(at(--topIndex)); m_error = "token stack is empty (BUG)"; return Token(); } const Token& TokenStack::top() { return top(0); } const Token& TokenStack::top(unsigned index) { return (topIndex > (int)index) ? at(topIndex - index - 1) : Token::null; } void TokenStack::ensureSpace() { int length = size(); while (topIndex >= length) { length += 10; resize(length); } } /** Remove \a count tokens from the top of the stack, add a stxAbstract token to the top * and adjust its text position and minimum precedence. * * \param minPrecedence minimum precedence to set the top token, or \c INVALID_PRECEDENCE * if this method should use the minimum value from the removed tokens. */ void TokenStack::reduce(int count, int minPrecedence) { // assert(itemCount() > count); QList tokens; for (int i = 0 ; i < count ; ++i) tokens.append(pop()); reduce(tokens, Token(Token::stxAbstract), minPrecedence); } /** Remove \a count tokens from the top of the stack, push \a top to the top * and adjust its text position and minimum precedence. * * \param minPrecedence minimum precedence to set the top token, or \c INVALID_PRECEDENCE * if this method should use the minimum value from the removed tokens. */ void TokenStack::reduce(int count, Token&& top, int minPrecedence) { // assert(itemCount() >= count); QList tokens; for (int i = 0 ; i < count ; ++i) tokens.append(pop()); reduce(tokens, std::forward(top), minPrecedence); } /** Push \a top to the top and adjust its text position and minimum precedence using \a tokens. * * \param minPrecedence minimum precedence to set the top token, or \c INVALID_PRECEDENCE * if this method should use the minimum value from the removed tokens. */ void TokenStack::reduce(QList tokens, Token&& top, int minPrecedence) { qSort(tokens.begin(), tokens.end(), tokenPositionCompare); bool computeMinPrec = (minPrecedence == INVALID_PRECEDENCE); int min_prec = computeMinPrec ? MAX_PRECEDENCE : minPrecedence; int start = -1, end = -1; for (Token& token : tokens) { if (computeMinPrec) { Token::Op op = token.asOperator(); if (op != Token::InvalidOp) { int prec = opPrecedence(op); if (prec < min_prec) min_prec = prec; } } if (token.pos() == -1 && token.size() == -1) continue; if (token.pos() == -1 || token.size() == -1) { continue; } if (start == -1) { start = token.pos(); } else { } end = token.pos() + token.size(); } if (start != -1) { top.setPos(start); top.setSize(end - start); } top.setMinPrecedence(min_prec); push(top); } // Helper function: return true for valid identifier character. static bool isIdentifier(QChar ch) { return ch.unicode() == '_' || ch.unicode() == '$' || ch.isLetter(); } // Helper function: return true for valid radix characters. bool Evaluator::isRadixChar(const QChar &ch) { if (Settings::instance()->isRadixCharacterBoth()) return ch.unicode() == '.' || ch.unicode() == ','; // There exist more than 2 radix characters actually: // U+0027 ' apostrophe // U+002C , comma // U+002E . full stop // U+00B7 · middle dot // U+066B ٫ arabic decimal separator // U+2396 ⎖ decimal separator key symbol return ch.unicode() == Settings::instance()->radixCharacter(); } // Helper function: return true for valid thousand separator characters. bool Evaluator::isSeparatorChar(const QChar &ch) { // Match everything that is not alphanumeric or an operator or NUL. static QRegExp s_separatorRE("[^a-zA-Z0-9\\+\\-\\*/\\^;\\(\\)%!=\\\\&\\|<>\\?#\\x0000]"); if (isRadixChar(ch)) return false; return s_separatorRE.exactMatch(ch); } QString Evaluator::fixNumberRadix(const QString& number) { int dotCount = 0; int commaCount = 0; QChar lastRadixChar; // First pass: count the number of dot and comma characters for (int i = 0 ; i < number.size() ; ++i) { QChar c = number[i]; if (isRadixChar(c)) { lastRadixChar = c; if (c == '.') ++dotCount; else if (c == ',') ++commaCount; else return QString(); // should not happen } } if (dotCount > 1) { return "error"; } // Decide which radix characters to ignore based on their occurrence count bool ignoreDot = dotCount != 1; bool ignoreComma = commaCount != 1; if (!ignoreDot && !ignoreComma) { // If both radix characters are present once, consider the last one as the radix point ignoreDot = lastRadixChar != '.'; ignoreComma = lastRadixChar != ','; } QChar radixChar; // Nul character by default if (!ignoreDot) radixChar = '.'; else if (!ignoreComma) radixChar = ','; // Second pass: write the result QString result = ""; for (int i = 0 ; i < number.size() ; ++i) { QChar c = number[i]; if (isRadixChar(c)) { if (c == radixChar) result.append('.'); } else result.append(c); } return result; } Evaluator* Evaluator::instance() { if (!s_evaluatorInstance) { s_evaluatorInstance = new Evaluator; qAddPostRoutine(s_deleteEvaluator); } return s_evaluatorInstance; } Evaluator::Evaluator() { reset(); } #define ADD_UNIT(name) \ setVariable(QString::fromUtf8(#name), Units::name(), Variable::BuiltIn) void Evaluator::initializeBuiltInVariables() { setVariable(QLatin1String("e"), DMath::e(), Variable::BuiltIn); setVariable(QString::fromUtf8("ℯ"), DMath::e(), Variable::BuiltIn); setVariable(QLatin1String("pi"), DMath::pi(), Variable::BuiltIn); setVariable(QString::fromUtf8("π"), DMath::pi(), Variable::BuiltIn); if(Settings::instance()->complexNumbers) { setVariable(QLatin1String("j"), DMath::i(), Variable::BuiltIn); } else if(hasVariable("j")) { unsetVariable("j", true); } QList unitList(Units::getList()); for(Unit u : unitList) { setVariable(u.name, u.value, Variable::BuiltIn); } initializeAngleUnits(); } void Evaluator::initializeAngleUnits() { if (Settings::instance()->angleUnit == 'r') { setVariable("radian", 1, Variable::BuiltIn); setVariable("degree", HMath::pi()/HNumber(180),Variable::BuiltIn); } else { setVariable("radian", HNumber(180)/HMath::pi(),Variable::BuiltIn); setVariable("degree", 1,Variable::BuiltIn); } } void Evaluator::setExpression(const QString& expr) { m_expression = expr; m_dirty = true; m_valid = false; m_error = QString(); } QString Evaluator::expression() const { return m_expression; } // Returns the validity. Note: empty expression is always invalid. bool Evaluator::isValid() { if (m_dirty) { Tokens tokens = scan(m_expression); if (!tokens.valid()) compile(tokens); else m_valid = false; } return m_valid; } void Evaluator::reset() { m_expression = QString(); m_dirty = true; m_valid = false; m_error = QString(); m_constants.clear(); m_codes.clear(); m_assignId = QString(); m_assignFunc = false; m_assignArg.clear(); m_session = NULL; m_functionsInUse.clear(); initializeBuiltInVariables(); } void Evaluator::setSession(Session *s) { m_session = s; } const Session *Evaluator::session() { return m_session; } QString Evaluator::error() const { return m_error; } // Returns list of token for the expression. // This triggers again the lexical analysis step. It is however preferable // (even when there's small performance penalty) because otherwise we need to // store parsed tokens all the time which serves no good purpose. Tokens Evaluator::tokens() const { return scan(m_expression); } Tokens Evaluator::scan(const QString& expr) const { // Associate character codes with the highest number base they might belong to const int DIGIT_MAP_COUNT = 128; static unsigned char s_digitMap[DIGIT_MAP_COUNT] = {0}; if (s_digitMap[0] == 0) { // Initialize the digits map std::fill_n(s_digitMap, DIGIT_MAP_COUNT, 255); for(int i = '0' ; i <= '9' ; ++i) s_digitMap[i] = i - '0' + 1; for(int i = 'a' ; i <= 'z' ; ++i) s_digitMap[i] = i - 'a' + 11; for(int i = 'A' ; i <= 'Z' ; ++i) s_digitMap[i] = i - 'A' + 11; } // Result. Tokens tokens; // Parsing state. enum { Init, Start, Finish, Bad, InNumberPrefix, InNumber, InExpIndicator, InExponent, InIdentifier, InNumberEnd } state; // Initialize variables. state = Init; int i = 0; QString ex = expr; QString tokenText; int tokenStart = 0; // includes leading spaces Token::Type type; int numberBase; int expStart = -1; // index of the exponent part in the expression QString expText; // start of the exponent text matching /E[\+\-]*/ // Force a terminator. ex.append(QChar()); // Main loop. while (state != Bad && state != Finish && i < ex.length()) { QChar ch = ex.at(i); switch (state) { case Init: tokenStart = i; tokenText = ""; state = Start; // State variables reset expStart = -1; expText = ""; // No break here on purpose (make sure Start is the next case) case Start: // Skip any whitespaces. if (ch.isSpace()) ++i; else if (ch == '?') // Comment. state = Finish; else if (ch.isDigit()) { // Check for number state = InNumberPrefix; } else if (ch == '#') { // Simple hexadecimal notation tokenText.append("0x"); numberBase = 16; state = InNumber; ++i; } else if (isRadixChar(ch)) { // Radix character? tokenText.append(ch); numberBase = 10; state = InNumber; ++i; } else if (isSeparatorChar(ch)) { // Leading separator, probably a number state = InNumberPrefix; } else if (ch.isNull()) // Terminator character. state = Finish; else if (isIdentifier(ch)) // Identifier or alphanumeric operator state = InIdentifier; else { // Look for operator match. int op; QString s; #if 0 // Check for three-char operator. s.append(ch).append(ex.at(i+1)).append(ex.at(i+2)); op = matchOperator(s); // Check for two-char operator. if (op == Token::InvalidOp) #endif { s = QString(ch).append(ex.at(i+1)); op = matchOperator(s); } // Check for one-char operator. if (op == Token::InvalidOp) { s = QString(ch); op = matchOperator(s); } // Any matched operator? if (op != Token::InvalidOp) { switch(op) { case Token::LeftPar: type = Token::stxOpenPar; break; case Token::RightPar: type = Token::stxClosePar; break; case Token::Semicolon: type = Token::stxSep; break; default: type = Token::stxOperator; } int len = s.length(); i += len; int tokenSize = i - tokenStart; tokens.append(Token(type, s.left(len), tokenStart, tokenSize)); state = Init; } else state = Bad; } //// Beginning with unknown alphanumeric? Could be identifier or function. //if (state == Bad && isIdentifier(ch)) // state = InIdentifier; break; /* Manage both identifier and alphanumeric operators */ case InIdentifier: // Consume as long as alpha, dollar sign, underscore, or digit. if (isIdentifier(ch) || ch.isDigit()) { tokenText.append(ex.at(i++)); } else { // We're done with identifier. int tokenSize = i - tokenStart; if (matchOperator(tokenText)) { // if token is an operator tokens.append(Token(Token::stxOperator, tokenText, tokenStart, tokenSize)); } else { // else, normal identifier tokens.append(Token(Token::stxIdentifier, tokenText, tokenStart, tokenSize)); } state = Init; } break; /* Find out the number base */ case InNumberPrefix: if (ch.isDigit()) { // Only consume the first digit and the second digit if the first was 0 tokenText.append(ex.at(i++)); if (tokenText != "0") { numberBase = 10; state = InNumber; } } else if (ch.toUpper() == 'E') { if (tokenText.endsWith("0")) { // Maybe exponent (tokenText is "0" or "-0") numberBase = 10; expText = "E"; expStart = i; ++i; state = InExpIndicator; } else { // Only leading separators state = Bad; } } else if (isRadixChar(ch)) { // Might be a radix point or a separator, collect it and decide later tokenText.append(ch); numberBase = 10; state = InNumber; ++i; } else if (ch.toUpper() == 'X' && tokenText == "0") { // Hexadecimal number numberBase = 16; tokenText.append('x'); ++i; state = InNumber; } else if (ch.toUpper() == 'B' && tokenText == "0") { // Binary number numberBase = 2; tokenText.append('b'); ++i; state = InNumber; } else if (ch.toUpper() == 'O' && tokenText == "0") { // Octal number numberBase = 8; tokenText.append('o'); ++i; state = InNumber; } else if (ch.toUpper() == 'D' && tokenText == "0") { // Decimal number (with prefix) numberBase = 10; tokenText.append('d'); ++i; state = InNumber; } else if (isSeparatorChar(ch)) { // Ignore thousand separators ++i; } else if (tokenText.isEmpty() && (ch == '+' || ch == '-')) { // Allow expressions like "$-10" or "$+10" if (ch == '-') tokenText.append('-'); ++i; } else { if (tokenText.endsWith("0")) { // We're done with integer number (tokenText is "0" or "-0") numberBase = 10; state = InNumberEnd; } else { // Only leading separators state = Bad; } } break; /* Parse the number digits */ case InNumber: { ushort c = ch.unicode(); bool isDigit = c < DIGIT_MAP_COUNT && (s_digitMap[c] <= numberBase); if (isDigit) { // Consume as long as it's a digit tokenText.append(ex.at(i++).toUpper()); } else if (numberBase == 10 && ch.toUpper() == 'E') { // Maybe exponent (only for decimal numbers) expText = "E"; expStart = i; ++i; tokenText = fixNumberRadix(tokenText); if (!tokenText.isNull()) state = InExpIndicator; else state = Bad; } else if (isRadixChar(ch)) { // Might be a radix point or a separator, collect it and decide later tokenText.append(ch); ++i; } else if (isSeparatorChar(ch)) { // Ignore thousand separators ++i; } else { // We're done with number tokenText = fixNumberRadix(tokenText); if (!tokenText.isNull()) state = InNumberEnd; else state = Bad; } break; } case InExpIndicator: if (ch == '+' || ch == '-') // Possible + or - right after E. expText.append(ex.at(i++)); else if (ch.isDigit()) {// Parse the exponent absolute value state = InExponent; tokenText.append(expText); } else if (isSeparatorChar(ch)) // Ignore thousand separators ++i; else {// Invalid thing here. // Rollback: might be an identifier used in implicit multiplication i = expStart; state = InNumberEnd; } break; case InExponent: if (ch.isDigit()) // Consume as long as it's a digit. tokenText.append(ex.at(i++)); else if (isSeparatorChar(ch)) // Ignore thousand separators ++i; else { // We're done with floating-point number. state = InNumberEnd; }; break; case InNumberEnd: { int tokenSize = i - tokenStart; tokens.append(Token(Token::stxNumber, tokenText, tokenStart, tokenSize)); // Make sure a number cannot be followed by another number if (ch.isDigit() || isRadixChar(ch) || ch == '#') state = Bad; else state = Init; break; } case Bad: tokens.setValid(false); break; default: break; }; } if (state == Bad) // Invalidating here too, because usually when we set state to Bad, the case Bad won't be run. tokens.setValid(false); return tokens; } void Evaluator::compile(const Tokens& tokens) { // Initialize variables. m_dirty = false; m_valid = false; m_codes.clear(); m_constants.clear(); m_identifiers.clear(); m_error = QString(); // Sanity check. if (tokens.count() == 0) return; TokenStack syntaxStack; QStack argStack; unsigned argCount = 1; for (int i = 0; i <= tokens.count() && !syntaxStack.hasError(); ++i) { // Helper token: InvalidOp is end-of-expression. Token token = (i < tokens.count()) ? tokens.at(i) : Token(Token::stxOperator); Token::Type tokenType = token.type(); if (tokenType >= Token::stxOperator) tokenType = Token::stxOperator; // Unknown token is invalid. if (tokenType == Token::stxUnknown) break; // Try to apply all parsing rules. // Repeat until no more rule applies. bool argHandled = false; while (!syntaxStack.hasError()) { bool ruleFound = false; // Rule for function last argument: id (arg) -> arg. if (!ruleFound && syntaxStack.itemCount() >= 4) { Token par2 = syntaxStack.top(); Token arg = syntaxStack.top(1); Token par1 = syntaxStack.top(2); Token id = syntaxStack.top(3); if (par2.asOperator() == Token::RightPar && arg.isOperand() && par1.asOperator() == Token::LeftPar && id.isIdentifier()) { ruleFound = true; syntaxStack.reduce(4, MAX_PRECEDENCE); m_codes.append(Opcode(Opcode::Function, argCount)); argCount = argStack.empty() ? 0 : argStack.pop(); } } // Are we entering a function? If token is operator, and stack already has: id (arg if (!ruleFound && !argHandled && tokenType == Token::stxOperator && syntaxStack.itemCount() >= 3) { Token arg = syntaxStack.top(); Token par = syntaxStack.top(1); Token id = syntaxStack.top(2); if (arg.isOperand() && par.asOperator() == Token::LeftPar && id.isIdentifier()) { ruleFound = true; argStack.push(argCount); argCount = 1; break; } } // Rule for postfix operators: Y POSTFIX -> Y // Condition: Y is not an operator, POSTFIX is a postfix op. // Since we evaluate from left to right, we need not check precedence at this point. if (!ruleFound && syntaxStack.itemCount() >= 2) { Token postfix = syntaxStack.top(); Token y = syntaxStack.top(1); if (postfix.isOperator() && y.isOperand()) switch (postfix.asOperator()) { case Token::Exclamation: ruleFound = true; syntaxStack.reduce(2); m_codes.append(Opcode(Opcode::Fact)); break; case Token::Percent: syntaxStack.pop(); m_constants.append(HNumber("0.01")); m_codes.append(Opcode(Opcode::Load, m_constants.count() - 1)); m_codes.append(Opcode(Opcode::Mul)); break; default:; } } // Rule for parenthesis: (Y) -> Y. if (!ruleFound && syntaxStack.itemCount() >= 3) { Token right = syntaxStack.top(); Token y = syntaxStack.top(1); Token left = syntaxStack.top(2); if (y.isOperand() && right.asOperator() == Token::RightPar && left.asOperator() == Token::LeftPar) { ruleFound = true; syntaxStack.reduce(3, MAX_PRECEDENCE); } } // Rule for simplified syntax for function e.g. "sin pi" or "cos 1.2" // i.e no need for parentheses like "sin(pi)" or "cos(1.2)". // Conditions: precedence of function reduction >= precedence of next token. // or next token is not an operator if (!ruleFound && syntaxStack.itemCount() >= 2) { Token arg = syntaxStack.top(); Token id = syntaxStack.top(1); if (arg.isOperand() && isFunction(id) && (!token.isOperator() || opPrecedence(Token::Function) >= opPrecedence(token.asOperator()))) { ruleFound = true; m_codes.append(Opcode(Opcode::Function, 1)); syntaxStack.reduce(2); } } // Rule for unary operator in simplified function syntax. This handles case like "sin -90". if (!ruleFound && syntaxStack.itemCount() >= 3) { Token x = syntaxStack.top(); Token op = syntaxStack.top(1); Token id = syntaxStack.top(2); if (x.isOperand() && isFunction(id) && (op.asOperator() == Token::Plus || op.asOperator() == Token::Minus)) { ruleFound = true; syntaxStack.reduce(2); if (op.asOperator() == Token::Minus) m_codes.append(Opcode(Opcode::Neg)); } } // Rule for function arguments, if token is ; or ): id (arg1 ; arg2 -> id (arg. // Must come before binary op rule, as it is a special case of the latter. if (!ruleFound && syntaxStack.itemCount() >= 5 && token.isOperator() && (token.asOperator() == Token::RightPar || token.asOperator() == Token::Semicolon)) { Token arg2 = syntaxStack.top(); Token sep = syntaxStack.top(1); Token arg1 = syntaxStack.top(2); Token par = syntaxStack.top(3); Token id = syntaxStack.top(4); if (arg2.isOperand() && sep.asOperator() == Token::Semicolon && arg1.isOperand() && par.asOperator() == Token::LeftPar && id.isIdentifier()) { ruleFound = true; argHandled = true; syntaxStack.reduce(3, MAX_PRECEDENCE); ++argCount; } } // Rule for function call with parentheses, but without argument e.g. "2*PI()". if (!ruleFound && syntaxStack.itemCount() >= 3) { Token par2 = syntaxStack.top(); Token par1 = syntaxStack.top(1); Token id = syntaxStack.top(2); if (par2.asOperator() == Token::RightPar && par1.asOperator() == Token::LeftPar && id.isIdentifier()) { ruleFound = true; syntaxStack.reduce(3, MAX_PRECEDENCE); m_codes.append(Opcode(Opcode::Function, 0)); } } // Rule for binary operator: A (op) B -> A. // Conditions: precedence of op >= precedence of token. // Action: push (op) to result e.g. "A * B" becomes "A" if token is operator "+". // Exception: for caret (power operator), if op is another caret // then the rule doesn't apply, e.g. "2^3^2" is evaluated as "2^(3^2)". // Exception: doesn't apply if B is a function name (to manage shift/reduce conflict // with simplified function syntax (resolves issue 600). if (!ruleFound && syntaxStack.itemCount() >= 3) { Token b = syntaxStack.top(); Token op = syntaxStack.top(1); Token a = syntaxStack.top(2); if (a.isOperand() && b.isOperand() && op.isOperator() && ((token.isOperator() && opPrecedence(op.asOperator()) >= opPrecedence(token.asOperator()) && token.asOperator() != Token::LeftPar && token.asOperator() != Token::Caret) // token is normal operator || (token.isOperand() // token may represent implicit multiplication && opPrecedence(op.asOperator()) >= opPrecedence(Token::Asterisk))) && !(isFunction(b))) { ruleFound = true; switch (op.asOperator()) { // Simple binary operations. case Token::Plus: m_codes.append(Opcode::Add); break; case Token::Minus: m_codes.append(Opcode::Sub); break; case Token::Asterisk: m_codes.append(Opcode::Mul); break; case Token::Slash: m_codes.append(Opcode::Div); break; case Token::Caret: m_codes.append(Opcode::Pow); break; case Token::Modulo: m_codes.append(Opcode::Modulo); break; case Token::Backslash: m_codes.append(Opcode::IntDiv); break; case Token::LeftShift: m_codes.append(Opcode::LSh); break; case Token::RightShift: m_codes.append(Opcode::RSh); break; case Token::Ampersand: m_codes.append(Opcode::BAnd); break; case Token::Pipe: m_codes.append(Opcode::BOr); break; case Token::RightArrow: { static const QRegExp unitNameNumberRE("(^[0-9e\\+\\-\\.,]|[0-9e\\.,]$)", Qt::CaseInsensitive); QString unitName = m_expression.mid(b.pos(), b.size()).simplified(); // Make sure the whole unit name can be used as a single operand in multiplications if (b.minPrecedence() < opPrecedence(Token::Asterisk)) unitName = "(" + unitName + ")"; // Protect the unit name if it starts or ends with a number else if (unitNameNumberRE.indexIn(unitName) != -1) unitName = "(" + unitName + ")"; m_codes.append(Opcode(Opcode::Conv, unitName)); break; } default: break; }; syntaxStack.reduce(3); } } #ifdef ALLOW_IMPLICIT_MULT /* Rule for implicit multiplication * Action: Treat as A * B. * Exception: doesn't apply if B is a function name (to manage shift/reduce conflict * with simplified function syntax (resolves issue 600). */ if(!ruleFound && syntaxStack.itemCount() >= 2) { Token b = syntaxStack.top(); Token a = syntaxStack.top(1); if(a.isOperand() && b.isOperand() && token.asOperator() != Token::LeftPar && ((token.isOperator() && opPrecedence(Token::Asterisk) >= opPrecedence(token.asOperator())) // token is normal operator || token.isOperand()) // token represents implicit multiplication && !(isFunction(b))) { ruleFound = true; syntaxStack.reduce(2, opPrecedence(Token::Asterisk)); m_codes.append(Opcode::Mul); } } #endif // Rule for unary operator: (op1) (op2) X -> (op1) X. // Conditions: op2 is unary. Current token has lower precedence than multiplication. if (!ruleFound && token.asOperator() != Token::LeftPar && syntaxStack.itemCount() >= 3) { Token x = syntaxStack.top(); Token op2 = syntaxStack.top(1); Token op1 = syntaxStack.top(2); if (x.isOperand() && op1.isOperator() && (op2.asOperator() == Token::Plus || op2.asOperator() == Token::Minus) && (token.isOperand() || opPrecedence(token.asOperator()) <= opPrecedence(Token::Asterisk))) { ruleFound = true; if (op2.asOperator() == Token::Minus) m_codes.append(Opcode(Opcode::Neg)); syntaxStack.reduce(2); } } // auxiliary rule for unary prefix operator: (op) X -> X // conditions: op is unary, op is first in syntax stack // action: create code for (op). Unary MINUS or PLUS are treated with the precedence of multiplication. if (!ruleFound && token.asOperator() != Token::LeftPar && syntaxStack.itemCount() == 2) { Token x = syntaxStack.top(); Token op = syntaxStack.top(1); if (x.isOperand() && (op.asOperator() == Token::Plus || op.asOperator() == Token::Minus) && ((token.isOperator() && opPrecedence(token.asOperator()) <= opPrecedence(Token::Asterisk)) || token.isOperand())) { ruleFound = true; if (op.asOperator() == Token::Minus) m_codes.append(Opcode(Opcode::Neg)); syntaxStack.reduce(2); } } if (!ruleFound) break; } // Can't apply rules anymore, push the token. if (1 || token.asOperator() != Token::Percent) syntaxStack.push(token); // For identifier, generate code to load from reference. if (tokenType == Token::stxIdentifier) { m_identifiers.append(token.text()); m_codes.append(Opcode(Opcode::Ref, m_identifiers.count() - 1)); } // For constants, generate code to load from a constant. if (tokenType == Token::stxNumber) { m_constants.append(token.asNumber()); m_codes.append(Opcode(Opcode::Load, m_constants.count() - 1)); } } m_valid = false; if (syntaxStack.hasError()) m_error = syntaxStack.error(); // syntaxStack must left only one operand and end-of-expression (i.e. InvalidOp). else if (syntaxStack.itemCount() == 2 && syntaxStack.top().isOperator() && syntaxStack.top().asOperator() == Token::InvalidOp && !syntaxStack.top(1).isOperator()) { m_valid = true; } // Bad parsing ? clean-up everything. if (!m_valid) { m_constants.clear(); m_codes.clear(); m_identifiers.clear(); } } Quantity Evaluator::evalNoAssign() { Quantity result; if (m_dirty) { // Reset m_assignId = QString(); m_assignFunc = false; m_assignArg.clear(); Tokens tokens = scan(m_expression); // Invalid expression? if (!tokens.valid()) { m_error = QString("invalid expression"); return Quantity(0); } // Variable assignment? if (tokens.count() > 2 && tokens.at(0).isIdentifier() && tokens.at(1).asOperator() == Token::Equal) { m_assignId = tokens.at(0).text(); tokens.erase(tokens.begin()); tokens.erase(tokens.begin()); } else if (tokens.count() > 2 && tokens.at(0).isIdentifier() && tokens.at(1).asOperator() == Token::LeftPar) { // Check for function assignment // Syntax: ident opLeftPar (ident (opSemiColon ident)*)? opRightPar opEqual int t; if (tokens.count() > 4 && tokens.at(2).asOperator() == Token::RightPar) { // Functions with no argument. t = 3; if (tokens.at(3).asOperator() == Token::Equal) m_assignFunc = true; } else { for (t = 2; t + 1 < tokens.count(); t += 2) { if (!tokens.at(t).isIdentifier()) break; m_assignArg.append(tokens.at(t).text()); if (tokens.at(t + 1).asOperator() == Token::RightPar) { // Check for the equal operator t += 2; if (t < tokens.count() && tokens.at(t).asOperator() == Token::Equal) m_assignFunc = true; break; } else if (tokens.at(t + 1).asOperator() != Token::Semicolon) break; } } if (m_assignFunc == true) { m_assignId = tokens.at(0).text(); for (; t >= 0; --t) tokens.erase(tokens.begin()); } else m_assignArg.clear(); } compile(tokens); if (!m_valid) { if (m_error.isEmpty()) m_error = QString("compile error"); return CNumber(0); } } result = exec(m_codes, m_constants, m_identifiers); return result; #undef DIGIT_MAP_COUNT } Quantity Evaluator::exec(const QVector& opcodes, const QVector& constants, const QStringList& identifiers) { QStack stack; QHash refs; int index; Quantity val1, val2; QVector args; QString fname; Function* function; const UserFunction* userFunction = NULL; for (int pc = 0; pc < opcodes.count(); ++pc) { const Opcode& opcode = opcodes.at(pc); index = opcode.index; switch (opcode.type) { // No operation. case Opcode::Nop: break; // Load a constant, push to stack. case Opcode::Load: val1 = constants.at(index); stack.push(val1); break; // Unary operation. case Opcode::Neg: if (stack.count() < 1) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val1 = checkOperatorResult(-val1); stack.push(val1); break; // Binary operation: take two values from stack, do the operation, push the result to stack. case Opcode::Add: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 + val1); stack.push(val2); break; case Opcode::Sub: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 - val1); stack.push(val2); break; case Opcode::Mul: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 * val1); stack.push(val2); break; case Opcode::Div: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 / val1); stack.push(val2); break; case Opcode::Pow: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(DMath::raise(val2, val1)); stack.push(val2); break; case Opcode::Fact: if (stack.count() < 1) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val1 = checkOperatorResult(DMath::factorial(val1)); stack.push(val1); break; case Opcode::Modulo: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 % val1); stack.push(val2); break; case Opcode::IntDiv: if (stack.count() < 2) { m_error = QString("invalid expression"); return CMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = checkOperatorResult(val2 / val1); stack.push(DMath::integer(val2)); break; case Opcode::LSh: if (stack.count() < 2) { m_error = QString("invalid expression"); return DMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = val2 << val1; stack.push(val2); break; case Opcode::RSh: if (stack.count() < 2) { m_error = QString("invalid expression"); return DMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 = val2 >> val1; stack.push(val2); break; case Opcode::BAnd: if (stack.count() < 2) { m_error = QString("invalid expression"); return DMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 &= val1; stack.push(val2); break; case Opcode::BOr: if (stack.count() < 2) { m_error = QString("invalid expression"); return DMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); val2 |= val1; stack.push(val2); break; case Opcode::Conv: if (stack.count() < 2) { m_error = QString("invalid expression"); return HMath::nan(); } val1 = stack.pop(); val2 = stack.pop(); if(val1.isZero()) { m_error = QString("unit must not be zero"); return HMath::nan(); } if(!val1.sameDimension(val2)) { m_error = QString("Conversion failed - dimension mismatch"); return HMath::nan(); } val2.setDisplayUnit(val1.numericValue(), opcode.text); stack.push(val2); break; // Reference. case Opcode::Ref: fname = identifiers.at(index); if (m_assignArg.contains(fname)) // Argument. stack.push(CMath::nan()); else if (hasVariable(fname)) // Variable. stack.push(getVariable(fname).value()); else { // Function. function = FunctionRepo::instance()->find(fname); if (function) { stack.push(CMath::nan()); refs.insert(stack.count(), fname); } else if (m_assignFunc) { // Allow arbitrary identifiers when declaring user functions. stack.push(CMath::nan()); refs.insert(stack.count(), fname); } else if (hasUserFunction(fname)) { stack.push(CMath::nan()); refs.insert(stack.count(), fname); } else { m_error = "" + fname + ": " + QString("unknown function or variable"); return CMath::nan(); } } break; // Calling function. case Opcode::Function: // Must do this first to avoid crash when using vars like functions. if (refs.isEmpty()) break; fname = refs.take(stack.count() - index); function = FunctionRepo::instance()->find(fname); userFunction = NULL; if (!function) { // Check if this is a valid user function call. userFunction = getUserFunction(fname); } if (!function && !userFunction && !m_assignFunc) { m_error = "" + fname + ": " + QString("unknown function or variable"); return CMath::nan(); } if (stack.count() < index) { m_error = QString("invalid expression"); return CMath::nan(); } args.clear(); for(; index; --index) args.insert(args.begin(), stack.pop()); // Remove the NaN we put on the stack (needed to make the user // functions declaration work with arbitrary identifiers). stack.pop(); // Show function signature if the user has given no argument (yet). if (userFunction) { if (!args.count() && userFunction->arguments().count() != 0) { m_error = QString::fromLatin1("%1(%2)").arg(userFunction->name()) .arg(userFunction->arguments().join(";")); return CMath::nan(); } } else if (function) { if (!args.count()) { m_error = QString::fromLatin1("%1(%2)").arg(fname).arg(function->usage()); return CMath::nan(); } } if (m_assignFunc) { // Allow arbitrary identifiers when declaring user functions. stack.push(CMath::nan()); } else if (userFunction) { stack.push(execUserFunction(userFunction, args)); if (!m_error.isEmpty()) return CMath::nan(); } else { stack.push(function->exec(args)); if (function->error()) { m_error = stringFromFunctionError(function); return CMath::nan(); } } break; default: break; } } // More than one value in stack? Unsuccesfull execution... if (stack.count() != 1) { m_error = QString("invalid expression"); return CMath::nan(); } return stack.pop(); } Quantity Evaluator::execUserFunction(const UserFunction* function, QVector& arguments) { /* TODO: * - replace user variables by user functions (with no argument) ? */ if (arguments.count() != function->arguments().count()) { m_error = "" + function->name() + ": " + QString("wrong number of arguments"); return CMath::nan(); } if (m_functionsInUse.contains(function->name())) { m_error = "" + function->name() + ": " + QString("recursion not supported"); return CMath::nan(); } m_functionsInUse.insert(function->name()); QVector newOpcodes; QVector newConstants = function->constants; // Copy // Replace references to function arguments by constants. for (int i = 0; i < function->opcodes.count(); ++i) { Opcode opcode = function->opcodes.at(i); if (opcode.type == Opcode::Ref) { // Check if the identifier is an argument name. QString name = function->identifiers.at(opcode.index); int argIdx = function->arguments().indexOf(name); if (argIdx >= 0) { // Replace the reference by a constant value. opcode = Opcode(Opcode::Load, newConstants.count()); newConstants.append(arguments.at(argIdx)); } } newOpcodes.append(opcode); } Quantity result = exec(newOpcodes, newConstants, function->identifiers); if (!m_error.isEmpty()) { // Tell the user where the error happened m_error = "" + function->name() + ": " + m_error; } m_functionsInUse.remove(function->name()); return result; } bool Evaluator::isUserFunctionAssign() const { return m_assignFunc; } bool Evaluator::isBuiltInVariable(const QString& id) const { // Defining variables with the same name as existing functions is not supported for now. if (FunctionRepo::instance()->find(id)) return true; if (!m_session || !m_session->hasVariable(id)) return false; return m_session->getVariable(id).type() == Variable::BuiltIn; } Quantity Evaluator::eval() { Quantity result = evalNoAssign(); // This sets m_assignId. if (!m_error.isEmpty()) return result; if (isBuiltInVariable(m_assignId)) { m_error = QString("%1 is a reserved name, please choose another").arg(m_assignId); return CMath::nan(); } // Handle user variable or function assignment. if (!m_assignId.isEmpty()) { if (m_assignFunc) { if(hasVariable(m_assignId)) { m_error = QString("%1 is a variable name, please choose another or delete the variable").arg(m_assignId); return CMath::nan(); } // Check that each argument is unique and not a reserved identifier. for (int i = 0; i < m_assignArg.count() - 1; ++i) { const QString &argName = m_assignArg.at(i); if (m_assignArg.indexOf(argName, i + 1) != -1) { m_error = QString("argument %1 is used more than once").arg(argName); return CMath::nan(); } if (isBuiltInVariable(argName)) { m_error = QString("%1 is a reserved name, please choose another").arg(argName); return CMath::nan(); } } if(m_codes.isEmpty()) return CMath::nan(); UserFunction userFunction(m_assignId, m_assignArg, m_expression.section("=", 1, 1).trimmed()); userFunction.constants = m_constants; userFunction.identifiers = m_identifiers; userFunction.opcodes = m_codes; setUserFunction(userFunction); } else { if(hasUserFunction(m_assignId)) { m_error = QString("%1 is a user function name, please choose another or delete the function").arg(m_assignId); return CMath::nan(); } setVariable(m_assignId, result); } } return result; } Quantity Evaluator::evalUpdateAns() { Quantity result = eval(); if (m_error.isEmpty() && !m_assignFunc) setVariable(QLatin1String("ans"), result, Variable::BuiltIn); return result; } void Evaluator::setVariable(const QString& id, Quantity value, Variable::Type type) { if(!m_session) m_session = new Session; m_session->addVariable(Variable(id, value, type)); } Variable Evaluator::getVariable(const QString& id) const { if (id.isEmpty() || !m_session) return Variable(QLatin1String(""), Quantity(0)); return m_session->getVariable(id); } bool Evaluator::hasVariable(const QString& id) const { if (id.isEmpty() || !m_session) return false; else return m_session->hasVariable(id); } void Evaluator::unsetVariable(const QString& id, bool force_builtin) { if(!m_session || (m_session->isBuiltInVariable(id) && ! force_builtin)) return; m_session->removeVariable(id); } QList Evaluator::getVariables() const { return m_session ? m_session->variablesToList() : QList(); } QList Evaluator::getUserDefinedVariables() const { QList result = getVariables(); auto iter = result.begin(); while (iter != result.end()) { if ((*iter).type() == Variable::BuiltIn) iter = result.erase(iter); else ++iter; } return result; } QList Evaluator::getUserDefinedVariablesPlusAns() const { QList result = getUserDefinedVariables(); Variable ans = getVariable(QLatin1String("ans")); if (!ans.identifier().isEmpty()) result.append(ans); return result; } void Evaluator::unsetAllUserDefinedVariables() { if(!m_session) return; Quantity ansBackup = getVariable(QLatin1String("ans")).value(); m_session->clearVariables(); setVariable(QLatin1String("ans"), ansBackup, Variable::BuiltIn); } static QRegularExpression s_superscriptPowersRE("(\\x{207B})?[\\x{2070}¹²³\\x{2074}-\\x{2079}]+"); static QHash s_superscriptPowersHash{ {L'\u207B', '-'}, {L'\u2070', '0'}, {L'\u00B9', '1'}, {L'\u00B2', '2'}, {L'\u00B3', '3'}, {L'\u2074', '4'}, {L'\u2075', '5'}, {L'\u2076', '6'}, {L'\u2077', '7'}, {L'\u2078', '8'}, {L'\u2079', '9'}, }; static void replaceSuperscriptPowersWithCaretEquivalent(QString& expr) { int offset = 0; while (true) { QRegularExpressionMatch match = s_superscriptPowersRE.match(expr, offset); if (!match.hasMatch()) break; QString power = match.captured(); for (int pos = power.size() - 1; pos >= 0; --pos) { QChar c = power.at(pos); power.replace(pos, 1, s_superscriptPowersHash.value(c, c)); } bool isNegative = match.capturedStart(1) != -1; if (isNegative) power = "^(" + power + ")"; else power = "^" + power; expr.replace(match.capturedStart(), match.capturedLength(), power); offset = match.capturedStart() + power.size(); } } QList Evaluator::getUserFunctions() const { return m_session ? m_session->UserFunctionsToList() : QList(); } void Evaluator::setUserFunction(const UserFunction &f) { if(!m_session) m_session = new Session; m_session->addUserFunction(f); } void Evaluator::unsetUserFunction(const QString& fname) { m_session->removeUserFunction(fname); } void Evaluator::unsetAllUserFunctions() { m_session->clearUserFunctions(); } bool Evaluator::hasUserFunction(const QString& fname) const { return (fname.isEmpty() || !m_session) ? false : m_session->hasUserFunction(fname); } const UserFunction *Evaluator::getUserFunction(const QString& fname) const { if(hasUserFunction(fname)) return m_session->getUserFunction(fname); else return NULL; } QString Evaluator::autoFix(const QString& expr) { int par = 0; QString result; // Strip off all funny characters. for(int c = 0; c < expr.length(); ++c) if (expr.at(c) >= QChar(32)) result.append(expr.at(c)); // No extra whitespaces at the beginning and at the end. result = result.trimmed(); // Strip trailing equal sign (=). while(result.endsWith("=")) result = result.left(result.length() - 1); replaceSuperscriptPowersWithCaretEquivalent(result); // Automagically close all parenthesis. Tokens tokens = Evaluator::scan(result); if (tokens.count()) { for(int i = 0; i < tokens.count(); ++i) if (tokens.at(i).asOperator() == Token::LeftPar) ++par; else if (tokens.at(i).asOperator() == Token::RightPar) --par; if (par < 0) par = 0; // If the scanner stops in the middle, do not bother to apply fix. const Token& lastToken = tokens.at(tokens.count() - 1); if (lastToken.pos() + lastToken.size() >= result.length()) while (par--) result.append(')'); } // Special treatment for simple function e.g. "cos" is regarded as "cos(ans)". if (!result.isEmpty()) { Tokens tokens = Evaluator::scan(result); if (tokens.count() == 1 && tokens.at(0).isIdentifier() && FunctionRepo::instance()->find(tokens.at(0).text())) { result.append("(ans)"); } } return result; } QString Evaluator::dump() { QString result; int c; if (m_dirty) { Tokens tokens = scan(m_expression); compile(tokens); } result = QString("Expression: [%1]\n").arg(m_expression); result.append(" Constants:\n"); for (c = 0; c < m_constants.count(); ++c) { Quantity val = m_constants.at(c); result += QString(" #%1 = %2\n").arg(c).arg(DMath::format(val, Quantity::Format::Fixed())); } result.append("\n"); result.append(" Identifiers:\n"); for(c = 0; c < m_identifiers.count(); ++c) { result += QString(" #%1 = %2\n").arg(c).arg(m_identifiers.at(c)); } result.append("\n"); result.append(" Code:\n"); for(int i = 0; i < m_codes.count(); ++i) { QString ctext; switch (m_codes.at(i).type) { case Opcode::Load: ctext = QString("Load #%1").arg(m_codes.at(i).index); break; case Opcode::Ref: ctext = QString("Ref #%1").arg(m_codes.at(i).index); break; case Opcode::Function: ctext = QString("Function (%1)").arg(m_codes.at(i).index); break; case Opcode::Add: ctext = "Add"; break; case Opcode::Sub: ctext = "Sub"; break; case Opcode::Mul: ctext = "Mul"; break; case Opcode::Div: ctext = "Div"; break; case Opcode::Neg: ctext = "Neg"; break; case Opcode::Pow: ctext = "Pow"; break; case Opcode::Fact: ctext = "Fact"; break; case Opcode::LSh: ctext = "LSh"; break; case Opcode::RSh: ctext = "RSh"; break; case Opcode::BAnd: ctext = "BAnd"; break; case Opcode::BOr: ctext = "BOr"; break; default: ctext = "Unknown"; break; } result.append(" ").append(ctext).append("\n"); } return result; } deepin-calculator-1.0.2/core/evaluator.h000066400000000000000000000140661325241207700202220ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2008, 2009, 2010, 2013 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_EVALUATOR_H #define CORE_EVALUATOR_H #include "core/functions.h" #include "math/hmath.h" #include "math/cmath.h" #include "math/quantity.h" #include #include #include #include #include #include #include #include "core/variable.h" #include "core/userfunction.h" class Session; class Token { public: enum Op { InvalidOp = 0, Plus, Minus, Asterisk, Slash, Backslash, Caret, Percent, Super0, Super1, Super2, Super3, Super4, Super5, Super6, Super7, Super8, Super9, LeftPar, RightPar, Semicolon, Exclamation, Equal, Modulo, LeftShift, RightShift, Ampersand, Pipe, RightArrow, Function }; /* Not really an operator but needed for managing shift/reduce conflicts */ enum Type { stxUnknown, stxNumber, stxIdentifier, stxAbstract, stxOperator, stxOpenPar, stxClosePar, stxSep}; // |<-------------isOperand------------->|<----------------isOperator----------------->| static const Token null; Token(Type type = stxUnknown, const QString& text = QString::null, int pos = -1, int size = -1); Token(const Token&); Quantity asNumber() const; Op asOperator() const; QString description() const; bool isNumber() const { return m_type == stxNumber; } bool isOperator() const { return m_type >= stxOperator; } bool isIdentifier() const { return m_type == stxIdentifier; } bool isOperand() const {return m_type == stxNumber || m_type == stxIdentifier || m_type == stxAbstract;} int pos() const { return m_pos; } void setPos(int pos) { m_pos = pos; } int size() const { return m_size; } void setSize(int size) { m_size = size; } QString text() const { return m_text; } Type type() const { return m_type; } int minPrecedence() const { return m_minPrecedence; } void setMinPrecedence(int minPrecedence) { m_minPrecedence = minPrecedence; } Token& operator=(const Token&); protected: /** Start position of the text that token represents in the expression (might include extra space characters). */ int m_pos; /** Size of text that token represents in the expression (might include extra space characters). */ int m_size; /** Precedence of the operator with the lowest precedence contained in this token. */ int m_minPrecedence; /** Normalized version of that token text (only valid when the token represents a single token). */ QString m_text; Type m_type; }; class Tokens : public QVector { public: Tokens() : QVector(), m_valid(true) { } bool valid() const { return m_valid; } void setValid(bool v) { m_valid = v; } #ifdef EVALUATOR_DEBUG void append(const Token&); #endif /* EVALUATOR_DEBUG */ protected: bool m_valid; }; class Evaluator : public QObject { Q_OBJECT public: static Evaluator* instance(); void reset(); void setSession(Session * s); const Session *session(); static bool isSeparatorChar(const QChar&); static bool isRadixChar(const QChar&); static QString fixNumberRadix(const QString&); QString autoFix(const QString&); QString dump(); QString error() const; Quantity eval(); Quantity evalNoAssign(); Quantity evalUpdateAns(); QString expression() const; bool isValid(); Tokens scan(const QString&) const; void setExpression(const QString&); Tokens tokens() const; bool isUserFunctionAssign() const; Variable getVariable(const QString&) const; QList getVariables() const; QList getUserDefinedVariables() const; QList getUserDefinedVariablesPlusAns() const; void setVariable(const QString&, Quantity, Variable::Type = Variable::UserDefined); void unsetVariable(const QString&, bool force_builtin = false); void unsetAllUserDefinedVariables(); bool isBuiltInVariable(const QString&) const; bool hasVariable(const QString&) const; void initializeBuiltInVariables(); void initializeAngleUnits(); QList getUserFunctions() const; void setUserFunction(const UserFunction & f); void unsetUserFunction(const QString&); void unsetAllUserFunctions(); bool hasUserFunction(const QString&) const; protected: void compile(const Tokens&); private: Evaluator(); Q_DISABLE_COPY(Evaluator) bool m_dirty; QString m_error; QString m_expression; bool m_valid; QString m_assignId; bool m_assignFunc; QStringList m_assignArg; QVector m_codes; QVector m_constants; QStringList m_identifiers; Session * m_session; QSet m_functionsInUse; const Quantity& checkOperatorResult(const Quantity&); static QString stringFromFunctionError(Function*); Quantity exec(const QVector& opcodes, const QVector& constants, const QStringList& identifiers); Quantity execUserFunction(const UserFunction* function, QVector& arguments); const UserFunction * getUserFunction(const QString&) const; bool isFunction(Token token) { return token.isIdentifier() && (FunctionRepo::instance()->find(token.text()) || hasUserFunction(token.text())); }; }; #endif deepin-calculator-1.0.2/core/functions.cpp000066400000000000000000001126311325241207700205600ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004-2006 Ariya Hidayat // Copyright (C) 2007, 2009 Wolf Lammen // Copyright (C) 2007-2009, 2013, 2014 @heldercorreia // Copyright (C) 2009 Andreas Scherer // Copyright (C) 2011 Enrico Rós // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "core/functions.h" #include "core/settings.h" #include "math/hmath.h" #include "math/cmath.h" #include #include #include #include #include #include #include #define FUNCTION_INSERT(ID) insert(new Function(#ID, function_ ## ID, this)) #define FUNCTION_USAGE(ID, USAGE) find(#ID)->setUsage(QString::fromLatin1(USAGE)); #define FUNCTION_USAGE_TR(ID, USAGE) find(#ID)->setUsage(USAGE); #define FUNCTION_NAME(ID, NAME) find(#ID)->setName(NAME) #define ENSURE_POSITIVE_ARGUMENT_COUNT() \ if (args.count() < 1) { \ f->setError(InvalidParamCount); \ return CMath::nan(InvalidParamCount); \ } #define ENSURE_ARGUMENT_COUNT(i) \ if (args.count() != (i)) { \ f->setError(InvalidParamCount); \ return CMath::nan(InvalidParamCount); \ } #define ENSURE_EITHER_ARGUMENT_COUNT(i, j) \ if (args.count() != (i) && args.count() != (j)) { \ f->setError(InvalidParamCount); \ return CMath::nan(InvalidParamCount); \ } #define ENSURE_SAME_DIMENSION() \ for(int i=0; isetError(OutOfDomain); \ return CMath::nan(); \ } #define ENSURE_REAL_ARGUMENTS() \ for (int i = 0; i < args.count(); i++) { \ ENSURE_REAL_ARGUMENT(i); \ } #define CONVERT_ARGUMENT_ANGLE(angle) \ if (Settings::instance()->angleUnit == 'd') { \ if (angle.isReal()) \ angle = DMath::deg2rad(angle); \ else { \ f->setError(OutOfDomain); \ return DMath::nan(); \ } \ } #define CONVERT_RESULT_ANGLE(result) \ if (Settings::instance()->angleUnit == 'd') { \ if (result.isReal()) \ result = DMath::rad2deg(result); \ else { \ f->setError(OutOfDomain); \ return DMath::nan(); \ } \ } static FunctionRepo* s_FunctionRepoInstance = 0; // FIXME: destructor seems not to be called static void s_deleteFunctions() { delete s_FunctionRepoInstance; } Quantity Function::exec(const Function::ArgumentList& args) { if (!m_ptr) return CMath::nan(); setError(Success); Quantity result = (*m_ptr)(this, args); if(result.error()) setError(result.error()); return result; } Quantity function_abs(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::abs(args.at(0)); } Quantity function_average(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin()+1, args.end(), *args.begin()) / Quantity(args.count()); } Quantity function_absdev(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); Quantity mean = function_average(f, args); if (mean.isNan()) return mean; // pass the error along Quantity acc = 0; for (int i = 0; i < args.count(); ++i) acc += DMath::abs(args.at(i) - mean); return acc / Quantity(args.count()); } Quantity function_int(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::integer(args[0]); } Quantity function_trunc(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_EITHER_ARGUMENT_COUNT(1, 2); Quantity num = args.at(0); if (args.count() == 2) { Quantity argprec = args.at(1); if (argprec != 0) { if (!argprec.isInteger()) { f->setError(OutOfDomain); return DMath::nan(); } int prec = argprec.numericValue().toInt(); if (prec) return DMath::trunc(num, prec); // The second parameter exceeds the integer limits. if (argprec < 0) return Quantity(0); return num; } } return DMath::trunc(num); } Quantity function_frac(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::frac(args[0]); } Quantity function_floor(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::floor(args[0]); } Quantity function_ceil(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::ceil(args[0]); } Quantity function_gcd(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); for (int i = 0; i < args.count(); ++i) if (!args[i].isInteger()) { f->setError(OutOfDomain); return DMath::nan(); } return std::accumulate(args.begin() + 1, args.end(), args.at(0), DMath::gcd); } Quantity function_round(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_EITHER_ARGUMENT_COUNT(1, 2); Quantity num = args.at(0); if (args.count() == 2) { Quantity argPrecision = args.at(1); if (argPrecision != 0) { if (!argPrecision.isInteger()) { f->setError(OutOfDomain); return DMath::nan(); } int prec = argPrecision.numericValue().toInt(); if (prec) return DMath::round(num, prec); // The second parameter exceeds the integer limits. if (argPrecision < 0) return Quantity(0); return num; } } return DMath::round(num); } Quantity function_sqrt(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::sqrt(args[0]); } Quantity function_variance(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT() Quantity mean = function_average(f, args); if (mean.isNan()) return mean; Quantity acc(DMath::real(args[0] - mean)*DMath::real(args[0] - mean) + DMath::imag(args[0] - mean)*DMath::imag(args[0] - mean)); for (int i = 1; i < args.count(); ++i) { Quantity q(args[i] - mean); acc += DMath::real(q)*DMath::real(q) + DMath::imag(q)*DMath::imag(q); } return acc / Quantity(args.count()); } Quantity function_stddev(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); return DMath::sqrt(function_variance(f, args)); } Quantity function_cbrt(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::cbrt(args[0]); } Quantity function_exp(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::exp(args[0]); } Quantity function_ln(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::ln(args[0]); } Quantity function_lg(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::lg(args[0]); } Quantity function_lb(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::lb(args[0]); } Quantity function_log(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::log(args.at(0), args.at(1)); } Quantity function_real(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::real(args.at(0)); } Quantity function_imag(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::imag(args.at(0)); } Quantity function_phase(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = DMath::phase(args.at(0)); CONVERT_RESULT_ANGLE(angle); return angle; } Quantity function_sin(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::sin(angle); } Quantity function_cos(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::cos(angle); } Quantity function_tan(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::tan(angle); } Quantity function_cot(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::cot(angle); } Quantity function_sec(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::sec(angle); } Quantity function_csc(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity angle = args.at(0); CONVERT_ARGUMENT_ANGLE(angle); return DMath::csc(angle); } Quantity function_arcsin(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity result; result = DMath::arcsin(args.at(0)); CONVERT_RESULT_ANGLE(result); return result; } Quantity function_arccos(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity result; result = DMath::arccos(args.at(0)); CONVERT_RESULT_ANGLE(result); return result; } Quantity function_arctan(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); Quantity result; result = DMath::arctan(args.at(0)); CONVERT_RESULT_ANGLE(result); return result; } Quantity function_arctan2(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(2); Quantity result; result = DMath::arctan2(args.at(0), args.at(1)); CONVERT_RESULT_ANGLE(result); return result; } Quantity function_sinh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::sinh(args[0]); } Quantity function_cosh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::cosh(args[0]); } Quantity function_tanh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::tanh(args[0]); } Quantity function_arsinh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::arsinh(args[0]); } Quantity function_arcosh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::arcosh(args[0]); } Quantity function_artanh(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::artanh(args[0]); } Quantity function_erf(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::erf(args[0]); } Quantity function_erfc(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::erfc(args[0]); } Quantity function_gamma(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::gamma(args[0]); } Quantity function_lngamma(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); ENSURE_REAL_ARGUMENT(0); return DMath::lnGamma(args[0]); } Quantity function_sgn(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::sgn(args[0]); } Quantity function_ncr(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::nCr(args.at(0), args.at(1)); } Quantity function_npr(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::nPr(args.at(0), args.at(1)); } Quantity function_degrees(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::rad2deg(args[0]); } Quantity function_radians(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return DMath::deg2rad(args[0]); } Quantity function_max(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT() ENSURE_REAL_ARGUMENTS() ENSURE_SAME_DIMENSION() return *std::max_element(args.begin(), args.end()); } Quantity function_median(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT() ENSURE_REAL_ARGUMENTS() ENSURE_SAME_DIMENSION() Function::ArgumentList sortedArgs = args; std::sort(sortedArgs.begin(), sortedArgs.end()); if ((args.count() & 1) == 1) return sortedArgs.at((args.count() - 1) / 2); const int centerLeft = args.count() / 2 - 1; return (sortedArgs.at(centerLeft) + sortedArgs.at(centerLeft + 1)) / Quantity(2); } Quantity function_min(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT() ENSURE_REAL_ARGUMENTS() ENSURE_SAME_DIMENSION() return *std::min_element(args.begin(), args.end()); } Quantity function_sum(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin(), args.end(), Quantity(0)); } Quantity function_product(Function* f, const Function::ArgumentList& args) { ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin(), args.end(), Quantity(1), std::multiplies()); } Quantity function_geomean(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); Quantity result = std::accumulate(args.begin(), args.end(), Quantity(1), std::multiplies()); if (result <= Quantity(0)) return DMath::nan(OutOfDomain); if (args.count() == 1) return result; if (args.count() == 2) return DMath::sqrt(result); return DMath::raise(result, Quantity(1)/Quantity(args.count())); } Quantity function_dec(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Decimal() + Quantity(args.at(0)).format()); } Quantity function_hex(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Fixed() + Quantity::Format::Hexadecimal() + Quantity(args.at(0)).format()); } Quantity function_oct(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Fixed() + Quantity::Format::Octal() + Quantity(args.at(0)).format()); } Quantity function_bin(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Fixed() + Quantity::Format::Binary() + Quantity(args.at(0)).format()); } Quantity function_cart(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Cartesian() + Quantity(args.at(0)).format()); } Quantity function_polar(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(1); return Quantity(args.at(0)).setFormat(Quantity::Format::Polar() + Quantity(args.at(0)).format()); } Quantity function_binompmf(Function* f, const Function::ArgumentList& args) { ENSURE_ARGUMENT_COUNT(3); return DMath::binomialPmf(args.at(0), args.at(1), args.at(2)); } Quantity function_binomcdf(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(3); return DMath::binomialCdf(args.at(0), args.at(1), args.at(2)); } Quantity function_binommean(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::binomialMean(args.at(0), args.at(1)); } Quantity function_binomvar(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::binomialVariance(args.at(0), args.at(1)); } Quantity function_hyperpmf(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(4); return DMath::hypergeometricPmf(args.at(0), args.at(1), args.at(2), args.at(3)); } Quantity function_hypercdf(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(4); return DMath::hypergeometricCdf(args.at(0), args.at(1), args.at(2), args.at(3)); } Quantity function_hypermean(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(3); return DMath::hypergeometricMean(args.at(0), args.at(1), args.at(2)); } Quantity function_hypervar(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(3); return DMath::hypergeometricVariance(args.at(0), args.at(1), args.at(2)); } Quantity function_poipmf(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::poissonPmf(args.at(0), args.at(1)); } Quantity function_poicdf(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::poissonCdf(args.at(0), args.at(1)); } Quantity function_poimean(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::poissonMean(args.at(0)); } Quantity function_poivar(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::poissonVariance(args.at(0)); } Quantity function_mask(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::mask(args.at(0), args.at(1)); } Quantity function_unmask(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::sgnext(args.at(0), args.at(1)); } Quantity function_not(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return ~args.at(0); } Quantity function_and(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin(), args.end(), Quantity(-1), std::mem_fun_ref(&Quantity::operator&)); } Quantity function_or(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin(), args.end(), Quantity(0), std::mem_fun_ref(&Quantity::operator|)); } Quantity function_xor(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_POSITIVE_ARGUMENT_COUNT(); return std::accumulate(args.begin(), args.end(), Quantity(0), std::mem_fun_ref(&Quantity::operator^)); } Quantity function_shl(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::ashr(args.at(0), -args.at(1)); } Quantity function_shr(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::ashr(args.at(0), args.at(1)); } Quantity function_idiv(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return DMath::idiv(args.at(0), args.at(1)); } Quantity function_mod(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(2); return args.at(0) % args.at(1); } Quantity function_ieee754_decode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_EITHER_ARGUMENT_COUNT(3, 4); if (args.count() == 3) { return DMath::decodeIeee754(args.at(0), args.at(1), args.at(2)); } else { return DMath::decodeIeee754(args.at(0), args.at(1), args.at(2), args.at(3)); } } Quantity function_ieee754_encode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_EITHER_ARGUMENT_COUNT(3, 4); if (args.count() == 3) { return DMath::encodeIeee754(args.at(0), args.at(1), args.at(2)); } else { return DMath::encodeIeee754(args.at(0), args.at(1), args.at(2), args.at(3)); } } Quantity function_ieee754_half_decode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::decodeIeee754(args.at(0), 5, 10); } Quantity function_ieee754_half_encode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::encodeIeee754(args.at(0), 5, 10); } Quantity function_ieee754_single_decode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::decodeIeee754(args.at(0), 8, 23); } Quantity function_ieee754_single_encode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::encodeIeee754(args.at(0), 8, 23); } Quantity function_ieee754_double_decode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::decodeIeee754(args.at(0), 11, 52); } Quantity function_ieee754_double_encode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::encodeIeee754(args.at(0), 11, 52); } Quantity function_ieee754_quad_decode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::decodeIeee754(args.at(0), 15, 112); } Quantity function_ieee754_quad_encode(Function* f, const Function::ArgumentList& args) { /* TODO : complex mode switch for this function */ ENSURE_ARGUMENT_COUNT(1); return DMath::encodeIeee754(args.at(0), 15, 112); } void FunctionRepo::createFunctions() { // Analysis. FUNCTION_INSERT(abs); FUNCTION_INSERT(absdev); FUNCTION_INSERT(average); FUNCTION_INSERT(bin); FUNCTION_INSERT(cbrt); FUNCTION_INSERT(ceil); FUNCTION_INSERT(dec); FUNCTION_INSERT(floor); FUNCTION_INSERT(frac); FUNCTION_INSERT(gamma); FUNCTION_INSERT(geomean); FUNCTION_INSERT(hex); FUNCTION_INSERT(int); FUNCTION_INSERT(lngamma); FUNCTION_INSERT(max); FUNCTION_INSERT(min); FUNCTION_INSERT(oct); FUNCTION_INSERT(product); FUNCTION_INSERT(round); FUNCTION_INSERT(sgn); FUNCTION_INSERT(sqrt); FUNCTION_INSERT(stddev); FUNCTION_INSERT(sum); FUNCTION_INSERT(trunc); FUNCTION_INSERT(variance); // Complex. FUNCTION_INSERT(real); FUNCTION_INSERT(imag); FUNCTION_INSERT(phase); FUNCTION_INSERT(polar); FUNCTION_INSERT(cart); // Discrete. FUNCTION_INSERT(gcd); FUNCTION_INSERT(ncr); FUNCTION_INSERT(npr); // Probability. FUNCTION_INSERT(binomcdf); FUNCTION_INSERT(binommean); FUNCTION_INSERT(binompmf); FUNCTION_INSERT(binomvar); FUNCTION_INSERT(erf); FUNCTION_INSERT(erfc); FUNCTION_INSERT(hypercdf); FUNCTION_INSERT(hypermean); FUNCTION_INSERT(hyperpmf); FUNCTION_INSERT(hypervar); FUNCTION_INSERT(median); FUNCTION_INSERT(poicdf); FUNCTION_INSERT(poimean); FUNCTION_INSERT(poipmf); FUNCTION_INSERT(poivar); // Trigonometry. FUNCTION_INSERT(arccos); FUNCTION_INSERT(arcosh); FUNCTION_INSERT(arsinh); FUNCTION_INSERT(artanh); FUNCTION_INSERT(arcsin); FUNCTION_INSERT(arctan); FUNCTION_INSERT(arctan2); FUNCTION_INSERT(cos); FUNCTION_INSERT(cosh); FUNCTION_INSERT(cot); FUNCTION_INSERT(csc); FUNCTION_INSERT(degrees); FUNCTION_INSERT(exp); FUNCTION_INSERT(lb); FUNCTION_INSERT(lg); FUNCTION_INSERT(ln); FUNCTION_INSERT(log); FUNCTION_INSERT(radians); FUNCTION_INSERT(sec); FUNCTION_INSERT(sin); FUNCTION_INSERT(sinh); FUNCTION_INSERT(tan); FUNCTION_INSERT(tanh); // Logic. FUNCTION_INSERT(mask); FUNCTION_INSERT(unmask); FUNCTION_INSERT(not); FUNCTION_INSERT(and); FUNCTION_INSERT(or); FUNCTION_INSERT(xor); FUNCTION_INSERT(shl); FUNCTION_INSERT(shr); FUNCTION_INSERT(idiv); FUNCTION_INSERT(mod); // IEEE-754. FUNCTION_INSERT(ieee754_decode); FUNCTION_INSERT(ieee754_encode); FUNCTION_INSERT(ieee754_half_decode); FUNCTION_INSERT(ieee754_half_encode); FUNCTION_INSERT(ieee754_single_decode); FUNCTION_INSERT(ieee754_single_encode); FUNCTION_INSERT(ieee754_double_decode); FUNCTION_INSERT(ieee754_double_encode); FUNCTION_INSERT(ieee754_quad_decode); FUNCTION_INSERT(ieee754_quad_encode); } FunctionRepo* FunctionRepo::instance() { if (!s_FunctionRepoInstance) { s_FunctionRepoInstance = new FunctionRepo; qAddPostRoutine(s_deleteFunctions); } return s_FunctionRepoInstance; } FunctionRepo::FunctionRepo() { createFunctions(); setNonTranslatableFunctionUsages(); retranslateText(); } void FunctionRepo::insert(Function* function) { if (!function) return; m_functions.insert(function->identifier().toUpper(), function); } Function* FunctionRepo::find(const QString& identifier) const { if (identifier.isNull()) return 0; return m_functions.value(identifier.toUpper(), 0); } QStringList FunctionRepo::getIdentifiers() const { QStringList result = m_functions.keys(); std::transform(result.begin(), result.end(), result.begin(), [](const QString& s) { return s.toLower(); }); return result; } void FunctionRepo::setNonTranslatableFunctionUsages() { FUNCTION_USAGE(abs, "x"); FUNCTION_USAGE(absdev, "x1; x2; ..."); FUNCTION_USAGE(arccos, "x"); FUNCTION_USAGE(and, "x1; x2; ..."); FUNCTION_USAGE(arcosh, "x"); FUNCTION_USAGE(arsinh, "x"); FUNCTION_USAGE(artanh, "x"); FUNCTION_USAGE(arcsin, "x"); FUNCTION_USAGE(arctan, "x"); FUNCTION_USAGE(arctan2, "x, y"); FUNCTION_USAGE(average, "x1; x2; ..."); FUNCTION_USAGE(bin, "n"); FUNCTION_USAGE(cart, "x"); FUNCTION_USAGE(cbrt, "x"); FUNCTION_USAGE(ceil, "x"); FUNCTION_USAGE(cos, "x"); FUNCTION_USAGE(cosh, "x"); FUNCTION_USAGE(cot, "x"); FUNCTION_USAGE(csc, "x"); FUNCTION_USAGE(dec, "x"); FUNCTION_USAGE(degrees, "x"); FUNCTION_USAGE(erf, "x"); FUNCTION_USAGE(erfc, "x"); FUNCTION_USAGE(exp, "x"); FUNCTION_USAGE(floor, "x"); FUNCTION_USAGE(frac, "x"); FUNCTION_USAGE(gamma, "x"); FUNCTION_USAGE(gcd, "n1; n2; ..."); FUNCTION_USAGE(geomean, "x1; x2; ..."); FUNCTION_USAGE(hex, "n"); FUNCTION_USAGE(ieee754_half_decode, "x"); FUNCTION_USAGE(ieee754_half_encode, "x"); FUNCTION_USAGE(ieee754_single_decode, "x"); FUNCTION_USAGE(ieee754_single_encode, "x"); FUNCTION_USAGE(ieee754_double_decode, "x"); FUNCTION_USAGE(ieee754_double_encode, "x"); FUNCTION_USAGE(ieee754_quad_decode, "x"); FUNCTION_USAGE(ieee754_quad_encode, "x"); FUNCTION_USAGE(int, "x"); FUNCTION_USAGE(imag, "x"); FUNCTION_USAGE(lb, "x"); FUNCTION_USAGE(lg, "x"); FUNCTION_USAGE(ln, "x"); FUNCTION_USAGE(lngamma, "x"); FUNCTION_USAGE(max, "x1; x2; ..."); FUNCTION_USAGE(median, "x1; x2; ..."); FUNCTION_USAGE(min, "x1; x2; ..."); FUNCTION_USAGE(ncr, "x1; x2"); FUNCTION_USAGE(not, "n"); FUNCTION_USAGE(npr, "x1; x2"); FUNCTION_USAGE(oct, "n"); FUNCTION_USAGE(or, "x1; x2; ..."); FUNCTION_USAGE(polar, "x"); FUNCTION_USAGE(product, "x1; x2; ..."); FUNCTION_USAGE(phase, "x"); FUNCTION_USAGE(radians, "x"); FUNCTION_USAGE(real, "x"); FUNCTION_USAGE(sec, "x)"); FUNCTION_USAGE(sgn, "x"); FUNCTION_USAGE(sin, "x"); FUNCTION_USAGE(sinh, "x"); FUNCTION_USAGE(sqrt, "x"); FUNCTION_USAGE(stddev, "x1; x2; ..."); FUNCTION_USAGE(sum, "x1; x2; ..."); FUNCTION_USAGE(tan, "x"); FUNCTION_USAGE(tanh, "x"); FUNCTION_USAGE(trunc, "x"); FUNCTION_USAGE(variance, "x1; x2; ..."); FUNCTION_USAGE(xor, "x1; x2; ..."); } void FunctionRepo::setTranslatableFunctionUsages() { FUNCTION_USAGE_TR(binomcdf, QString("max; trials; probability")); FUNCTION_USAGE_TR(binommean, QString("trials; probability")); FUNCTION_USAGE_TR(binompmf, QString("hits; trials; probability")); FUNCTION_USAGE_TR(binomvar, QString("trials; probability")); FUNCTION_USAGE_TR(hypercdf, QString("max; total; hits; trials")); FUNCTION_USAGE_TR(hypermean, QString("total; hits; trials")); FUNCTION_USAGE_TR(hyperpmf, QString("count; total; hits; trials")); FUNCTION_USAGE_TR(hypervar, QString("total; hits; trials")); FUNCTION_USAGE_TR(idiv, QString("dividend; divisor")); FUNCTION_USAGE_TR(ieee754_decode, QString("x; exponent_bits; significand_bits [; exponent_bias]")); FUNCTION_USAGE_TR(ieee754_encode, QString("x; exponent_bits; significand_bits [; exponent_bias]")); FUNCTION_USAGE_TR(log, QString("base; x")); FUNCTION_USAGE_TR(mask, QString("n; bits")); FUNCTION_USAGE_TR(mod, QString("value; modulo")); FUNCTION_USAGE_TR(poicdf, QString("events; average_events")); FUNCTION_USAGE_TR(poimean, QString("average_events")); FUNCTION_USAGE_TR(poipmf, QString("events; average_events")); FUNCTION_USAGE_TR(poivar, QString("average_events")); FUNCTION_USAGE_TR(round, QString("x [; precision]")); FUNCTION_USAGE_TR(shl, QString("n; bits")); FUNCTION_USAGE_TR(shr, QString("n; bits")); FUNCTION_USAGE_TR(unmask, QString("n; bits")); } void FunctionRepo::setFunctionNames() { FUNCTION_NAME(abs, QString("Absolute Value")); FUNCTION_NAME(absdev, QString("Absolute Deviation")); FUNCTION_NAME(arccos, QString("Arc Cosine")); FUNCTION_NAME(and, QString("Logical AND")); FUNCTION_NAME(arcosh, QString("Area Hyperbolic Cosine")); FUNCTION_NAME(arsinh, QString("Area Hyperbolic Sine")); FUNCTION_NAME(artanh, QString("Area Hyperbolic Tangent")); FUNCTION_NAME(arcsin, QString("Arc Sine")); FUNCTION_NAME(arctan, QString("Arc Tangent")); FUNCTION_NAME(arctan2, QString("Arc Tangent with two Arguments")); FUNCTION_NAME(average, QString("Average (Arithmetic Mean)")); FUNCTION_NAME(bin, QString("Convert to Binary Representation")); FUNCTION_NAME(binomcdf, QString("Binomial Cumulative Distribution Function")); FUNCTION_NAME(binommean, QString("Binomial Distribution Mean")); FUNCTION_NAME(binompmf, QString("Binomial Probability Mass Function")); FUNCTION_NAME(binomvar, QString("Binomial Distribution Variance")); FUNCTION_NAME(cart, QString("Convert to Cartesian Notation")); FUNCTION_NAME(cbrt, QString("Cube Root")); FUNCTION_NAME(ceil, QString("Ceiling")); FUNCTION_NAME(cos, QString("Cosine")); FUNCTION_NAME(cosh, QString("Hyperbolic Cosine")); FUNCTION_NAME(cot, QString("Cotangent")); FUNCTION_NAME(csc, QString("Cosecant")); FUNCTION_NAME(dec, QString("Convert to Decimal Representation")); FUNCTION_NAME(degrees, QString("Degrees of Arc")); FUNCTION_NAME(erf, QString("Error Function")); FUNCTION_NAME(erfc, QString("Complementary Error Function")); FUNCTION_NAME(exp, QString("Exponential")); FUNCTION_NAME(floor, QString("Floor")); FUNCTION_NAME(frac, QString("Fractional Part")); FUNCTION_NAME(gamma, QString("Extension of Factorials [= (x-1)!]")); FUNCTION_NAME(gcd, QString("Greatest Common Divisor")); FUNCTION_NAME(geomean, QString("Geometric Mean")); FUNCTION_NAME(hex, QString("Convert to Hexadecimal Representation")); FUNCTION_NAME(hypercdf, QString("Hypergeometric Cumulative Distribution Function")); FUNCTION_NAME(hypermean, QString("Hypergeometric Distribution Mean")); FUNCTION_NAME(hyperpmf, QString("Hypergeometric Probability Mass Function")); FUNCTION_NAME(hypervar, QString("Hypergeometric Distribution Variance")); FUNCTION_NAME(idiv, QString("Integer Quotient")); FUNCTION_NAME(int, QString("Integer Part")); FUNCTION_NAME(imag, QString("Imaginary Part")); FUNCTION_NAME(ieee754_decode, QString("Decode IEEE-754 Binary Value")); FUNCTION_NAME(ieee754_encode, QString("Encode IEEE-754 Binary Value")); FUNCTION_NAME(ieee754_half_decode, QString("Decode 16-bit Half-Precision Value")); FUNCTION_NAME(ieee754_half_encode, QString("Encode 16-bit Half-Precision Value")); FUNCTION_NAME(ieee754_single_decode, QString("Decode 32-bit Single-Precision Value")); FUNCTION_NAME(ieee754_single_encode, QString("Encode 32-bit Single-Precision Value")); FUNCTION_NAME(ieee754_double_decode, QString("Decode 64-bit Double-Precision Value")); FUNCTION_NAME(ieee754_double_encode, QString("Encode 64-bit Double-Precision Value")); FUNCTION_NAME(ieee754_quad_decode, QString("Decode 128-bit Quad-Precision Value")); FUNCTION_NAME(ieee754_quad_encode, QString("Encode 128-bit Quad-Precision Value")); FUNCTION_NAME(lb, QString("Binary Logarithm")); FUNCTION_NAME(lg, QString("Common Logarithm")); FUNCTION_NAME(ln, QString("Natural Logarithm")); FUNCTION_NAME(lngamma, "ln(abs(Gamma))"); FUNCTION_NAME(log, QString("Logarithm to Arbitrary Base")); FUNCTION_NAME(mask, QString("Mask to a bit size")); FUNCTION_NAME(max, QString("Maximum")); FUNCTION_NAME(median, QString("Median Value (50th Percentile)")); FUNCTION_NAME(min, QString("Minimum")); FUNCTION_NAME(mod, QString("Modulo")); FUNCTION_NAME(ncr, QString("Combination (Binomial Coefficient)")); FUNCTION_NAME(not, QString("Logical NOT")); FUNCTION_NAME(npr, QString("Permutation (Arrangement)")); FUNCTION_NAME(oct, QString("Convert to Octal Representation")); FUNCTION_NAME(or, QString("Logical OR")); FUNCTION_NAME(phase, QString("Phase of Complex Number")); FUNCTION_NAME(poicdf, QString("Poissonian Cumulative Distribution Function")); FUNCTION_NAME(poimean, QString("Poissonian Distribution Mean")); FUNCTION_NAME(poipmf, QString("Poissonian Probability Mass Function")); FUNCTION_NAME(poivar, QString("Poissonian Distribution Variance")); FUNCTION_NAME(polar, QString("Convert to Polar Notation")); FUNCTION_NAME(product, QString("Product")); FUNCTION_NAME(radians, QString("Radians")); FUNCTION_NAME(real, QString("Real Part")); FUNCTION_NAME(round, QString("Rounding")); FUNCTION_NAME(sec, QString("Secant")); FUNCTION_NAME(shl, QString("Arithmetic Shift Left")); FUNCTION_NAME(shr, QString("Arithmetic Shift Right")); FUNCTION_NAME(sgn, QString("Signum")); FUNCTION_NAME(sin, QString("Sine")); FUNCTION_NAME(sinh, QString("Hyperbolic Sine")); FUNCTION_NAME(sqrt, QString("Square Root")); FUNCTION_NAME(stddev, QString("Standard Deviation (Square Root of Variance)")); FUNCTION_NAME(sum, QString("Sum")); FUNCTION_NAME(tan, QString("Tangent")); FUNCTION_NAME(tanh, QString("Hyperbolic Tangent")); FUNCTION_NAME(trunc, QString("Truncation")); FUNCTION_NAME(unmask, QString("Sign-extend a value")); FUNCTION_NAME(variance, QString("Variance")); FUNCTION_NAME(xor, QString("Logical XOR")); } void FunctionRepo::retranslateText() { setFunctionNames(); setTranslatableFunctionUsages(); } deepin-calculator-1.0.2/core/functions.h000066400000000000000000000050111325241207700202160ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2008-2009, 2013 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_FUNCTION_H #define CORE_FUNCTION_H #include "core/errors.h" #include "math/quantity.h" #include #include #include #include class Function; class Function : public QObject { Q_OBJECT public: typedef QVector ArgumentList; typedef Quantity (*FunctionImpl)(Function*, const ArgumentList&); Function(const QString& identifier, FunctionImpl ptr, QObject* parent = 0) : QObject(parent) , m_identifier(identifier) , m_ptr(ptr) { } const QString& identifier() const { return m_identifier; } const QString& name() const { return m_name; } const QString& usage() const { return m_usage; } Error error() const { return m_error; } Quantity exec(const ArgumentList&); void setName(const QString& name) { m_name = name; } void setUsage(const QString& usage) { m_usage = usage; } void setError(Error error) { m_error = error; } private: Q_DISABLE_COPY(Function) Function(); QString m_identifier; QString m_name; QString m_usage; Error m_error; FunctionImpl m_ptr; }; class FunctionRepo : public QObject { Q_OBJECT public: static FunctionRepo* instance(); void insert(Function*); QStringList getIdentifiers() const; Function* find(const QString& identifier) const; public slots: void retranslateText(); private: Q_DISABLE_COPY(FunctionRepo) FunctionRepo(); void createFunctions(); void setFunctionNames(); void setNonTranslatableFunctionUsages(); void setTranslatableFunctionUsages(); QHash m_functions; }; #endif // CORE_FUNCTION_H deepin-calculator-1.0.2/core/numberformatter.cpp000066400000000000000000000057111325241207700217640ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2013 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "../core/numberformatter.h" #include "core/settings.h" #include "../math/quantity.h" QString NumberFormatter::format(Quantity q) { Settings* settings = Settings::instance(); Quantity::Format format = q.format(); if (format.base == Quantity::Format::Base::Null) { switch (settings->resultFormat) { case 'b': format.base = Quantity::Format::Base::Binary; format.mode = Quantity::Format::Mode::Fixed; break; case 'o': format.base = Quantity::Format::Base::Octal; format.mode = Quantity::Format::Mode::Fixed; break; case 'h': format.base = Quantity::Format::Base::Hexadecimal; format.mode = Quantity::Format::Mode::Fixed; break; case 'n': format.base = Quantity::Format::Base::Decimal; format.mode = Quantity::Format::Mode::Engineering; break; case 'f': format.base = Quantity::Format::Base::Decimal; format.mode = Quantity::Format::Mode::Fixed; break; case 'e': format.base = Quantity::Format::Base::Decimal; format.mode = Quantity::Format::Mode::Scientific; break; case 'g': default: format.base = Quantity::Format::Base::Decimal; format.mode = Quantity::Format::Mode::General; break; } } if (format.mode == Quantity::Format::Mode::Null) format.mode = Quantity::Format::Mode::General; if (format.precision == Quantity::Format::PrecisionNull) format.precision = settings->resultPrecision; if (format.notation == Quantity::Format::Notation::Null) { if (settings->resultFormatComplex == 'c') format.notation = Quantity::Format::Notation::Cartesian; else if (settings->resultFormatComplex == 'p') format.notation = Quantity::Format::Notation::Polar; } QString result = DMath::format(q, format); if (settings->radixCharacter() == ',') result.replace('.', ','); return result; } deepin-calculator-1.0.2/core/numberformatter.h000066400000000000000000000023161325241207700214270ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2013 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_NUMBERFORMATTER_H #define CORE_NUMBERFORMATTER_H #include "../math/quantity.h" #include struct NumberFormatter { static QString format(HNumber &num) { return format(Quantity(num)); } static QString format(CNumber &num) { return format(Quantity(num)); } static QString format(Quantity); }; #endif deepin-calculator-1.0.2/core/opcode.cpp000066400000000000000000000000241325241207700200110ustar00rootroot00000000000000#include "opcode.h" deepin-calculator-1.0.2/core/opcode.h000066400000000000000000000030761325241207700174700ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2008, 2009, 2010, 2013 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_OPCODE_H #define CORE_OPCODE_H #include class Opcode { public: enum Type { Nop, Load, Ref, Function, Add, Sub, Neg, Mul, Div, Pow, Fact, Modulo, IntDiv, LSh, RSh, BAnd, BOr, Conv }; Type type; unsigned index; // TODO: this is only needed for Conv Op. Maybe refactor this to a smarter place? // TODO: only keep a pointer to the string QString text; Opcode() : type(Nop), index(0) {} Opcode(Type t) : type(t), index(0) {} Opcode(Type t, QString txt) : type(t), index(0), text(txt) {} Opcode(Type t, unsigned i): type(t), index(i) {} }; #endif // CORE_OPCODE_H deepin-calculator-1.0.2/core/session.cpp000066400000000000000000000125341325241207700202340ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "session.h" #include "sessionhistory.h" #include "variable.h" #include "evaluator.h" #include #include #include "functions.h" void Session::serialize(QJsonObject &json) const { json["version"] = QString("0.1"); // history QJsonArray hist_entries; for(int i=0; i i(m_variables); while(i.hasNext()) { i.next(); QJsonObject curr_entry_obj; //ignore builtin variables if(i.value().type()==Variable::BuiltIn && i.value().identifier()!="ans") continue; i.value().serialize(curr_entry_obj); var_entries.append(curr_entry_obj); } json["variables"] = var_entries; // functions QJsonArray func_entries; QHashIterator j(m_userFunctions); while(j.hasNext()) { j.next(); QJsonObject curr_entry_obj; j.value().serialize(curr_entry_obj); func_entries.append(curr_entry_obj); } json["functions"] = func_entries; } int Session::deSerialize(const QJsonObject &json, bool merge=false) { QString version = json["version"].toString(); if(!merge) { m_history.clear(); m_variables.clear(); } Evaluator::instance()->initializeBuiltInVariables(); if (json.contains("history")) { QJsonArray hist_obj = json["history"].toArray(); int n = hist_obj.size(); for(int i=0; i Session::variablesToList() const { return m_variables.values(); } bool Session::isBuiltInVariable(const QString & id) const { // Defining variables with the same name as existing functions is not supported for now. if(FunctionRepo::instance()->find(id)) return true; if(!m_variables.contains(id)) return false; return m_variables.value(id).type() == Variable::BuiltIn; } void Session::addHistoryEntry(const HistoryEntry &entry) { m_history.append(entry); } void Session::insertHistoryEntry(const int index, const HistoryEntry &entry) { m_history.insert(index, entry); } void Session::removeHistoryEntryAt(const int index) { m_history.removeAt(index); } HistoryEntry Session::historyEntryAt(const int index) const { return m_history.at(index); } void Session::clearHistory() { m_history.clear(); } void Session::addUserFunction(const UserFunction &func) { if(func.opcodes.isEmpty()) { // We need to compile the function, so pretend the user typed it. Evaluator::instance()->setExpression(func.name() + "(" + func.arguments().join(";") + ")=" + func.expression()); Evaluator::instance()->eval(); } else { QString name = func.name(); m_userFunctions[name] = func; } } void Session::removeUserFunction(const QString &str) { m_userFunctions.remove(str); } void Session::clearUserFunctions() { m_userFunctions.clear(); } bool Session::hasUserFunction(const QString &str) const { return m_userFunctions.contains(str); } QList Session::UserFunctionsToList() const { return m_userFunctions.values(); } const UserFunction * Session::getUserFunction(const QString &fname) const { return &*m_userFunctions.find(fname); } deepin-calculator-1.0.2/core/session.h000066400000000000000000000047531325241207700177050ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_SESSION_H #define CORE_SESSION_H #include "../math/hmath.h" #include "sessionhistory.h" #include "variable.h" #include "userfunction.h" #include #include #include #include class Session { private: typedef QList History ; typedef QHash VariableContainer; typedef QHash FunctionContainer; History m_history; VariableContainer m_variables; FunctionContainer m_userFunctions; public: Session() {} Session(QJsonObject & json); void load(); void save(); void serialize(QJsonObject &json) const; int deSerialize(const QJsonObject & json, bool merge); void addVariable(const Variable & var); bool hasVariable(const QString & id) const; void removeVariable(const QString & id); void clearVariables(); Variable getVariable(const QString & id) const; QList variablesToList() const; bool isBuiltInVariable(const QString &id) const; void addHistoryEntry(const HistoryEntry & entry); void insertHistoryEntry(const int index, const HistoryEntry & entry); void removeHistoryEntryAt(const int index); HistoryEntry historyEntryAt(const int index) const; QList historyToList() const {return m_history;} void clearHistory(); void addUserFunction(const UserFunction & func); void removeUserFunction(const QString & str); void clearUserFunctions(); bool hasUserFunction(const QString & str) const; QList UserFunctionsToList() const; const UserFunction * getUserFunction(const QString & fname) const; }; #endif // CORE_SESSION_H deepin-calculator-1.0.2/core/sessionhistory.cpp000066400000000000000000000032331325241207700216520ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "sessionhistory.h" HistoryEntry::HistoryEntry(const QJsonObject & json) { deSerialize(json); } QString HistoryEntry::expr() const { return m_expr; } Quantity HistoryEntry::result() const { return m_result; } void HistoryEntry::setExpr(const QString & e) { m_expr = e; } void HistoryEntry::setResult(const Quantity & n) { m_result = n; } void HistoryEntry::serialize(QJsonObject & json) const { json["expression"] = m_expr; QJsonObject result; m_result.serialize(result); json["result"] = result; return; } void HistoryEntry::deSerialize(const QJsonObject & json) { *this = HistoryEntry(); if (json.contains("expression")) m_expr = json["expression"].toString(); if (json.contains("result")) m_result = Quantity(json["result"].toObject()); return; } deepin-calculator-1.0.2/core/sessionhistory.h000066400000000000000000000031371325241207700213220ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_SESSIONHISTORY_H #define CORE_SESSIONHISTORY_H #include #include #include #include "math/quantity.h" class HistoryEntry { private: QString m_expr; Quantity m_result; public: HistoryEntry() : m_expr(""), m_result(0) {} HistoryEntry(const QJsonObject & json); HistoryEntry(const QString & expr, const Quantity & num) : m_expr(expr), m_result(num) {} HistoryEntry(const HistoryEntry & other) : m_expr(other.m_expr), m_result(other.m_result) {} void setExpr(const QString & e); void setResult(const Quantity & n); QString expr() const; Quantity result() const; void serialize(QJsonObject & json) const; void deSerialize(const QJsonObject & json); }; #endif // CORE_SESSIONHISTORY_H deepin-calculator-1.0.2/core/settings.cpp000066400000000000000000000047751325241207700204210ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004, 2005, 2007, 2008 Ariya Hidayat // Copyright (C) 2005-2006 Johan Thelin // Copyright (C) 2007-2016 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "core/settings.h" #include "math/floatconfig.h" #include #include #include #include #include #include // The current config revision. Based on the application version number // ('1200' corresponds to 0.12.0, '10300' would be 1.3.0 etc.). When making // a backwards-incompatible change to the config format, bump this number to // the next release (if not already happened), then update the migration code // in createQSettings. Don't bump the config version unnecessarily for // releases that don't contain incompatible changes. static const int ConfigVersion = 1200; static const char* DefaultColorScheme = "Terminal"; static Settings* s_settingsInstance = 0; static char s_radixCharacter = 0; static void s_deleteSettings() { delete s_settingsInstance; } Settings* Settings::instance() { if (!s_settingsInstance) { s_settingsInstance = new Settings; qAddPostRoutine(s_deleteSettings); } return s_settingsInstance; } Settings::Settings() { } char Settings::radixCharacter() const { if (isRadixCharacterAuto() || isRadixCharacterBoth()) return QLocale().decimalPoint().toLatin1(); return s_radixCharacter; } bool Settings::isRadixCharacterAuto() const { return s_radixCharacter == 0; } bool Settings::isRadixCharacterBoth() const { return s_radixCharacter == '*'; } void Settings::setRadixCharacter(char c) { s_radixCharacter = (c != ',' && c != '.' && c != '*') ? 0 : c; } deepin-calculator-1.0.2/core/settings.h000066400000000000000000000045321325241207700200550ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2005-2006 Johan Thelin // Copyright (C) 2007-2016 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_SETTINGS_H #define CORE_SETTINGS_H #include #include #include #include class Settings { public: static Settings* instance(); char radixCharacter() const; // 0 or '*': Automatic. void setRadixCharacter(char c = 0); bool isRadixCharacterAuto() const; bool isRadixCharacterBoth() const; bool complexNumbers; char angleUnit; // 'r': radian; 'd': degree. char resultFormat; int resultPrecision; // See HMath documentation. char resultFormatComplex; // 'c' cartesian; 'p' polar. bool autoAns; bool autoCalc; bool autoCompletion; int digitGrouping; bool sessionSave; bool leaveLastExpression; bool syntaxHighlighting; bool windowAlwaysOnTop; bool autoResultToClipboard; bool windowPositionSave; bool constantsDockVisible; bool functionsDockVisible; bool historyDockVisible; bool keypadVisible; bool formulaBookDockVisible; bool statusBarVisible; bool variablesDockVisible; bool userFunctionsDockVisible; bool windowOnfullScreen; bool bitfieldVisible; QString colorScheme; QString displayFont; QString language; QByteArray windowState; QByteArray windowGeometry; QByteArray manualWindowGeometry; private: Settings(); Q_DISABLE_COPY(Settings) }; #endif deepin-calculator-1.0.2/core/userfunction.cpp000066400000000000000000000106621325241207700212750ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "core/userfunction.h" #include "core/evaluator.h" #include "core/opcode.h" #include //#define SAVE_COMPILED_FORM UserFunction::UserFunction(const QJsonObject &json) : UserFunction() { if (json.contains("name")) m_name = json["name"].toString(); if (json.contains("args")) { const QJsonArray args_json = json["args"].toArray(); int n = json["args"].toArray().size(); for(int i=0; i(codes_json[i].toObject()["t"].toInt()), codes_json[i].toObject()["i"].toInt()); if(codes_json[i].toObject().contains("text")) opcode.text = codes_json[i].toObject()["text"].toString(); opcodes.append(opcode); } const QJsonArray & const_json = json["constants"].toArray(); for(int i=0; i // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_USERFUNCTION_H #define CORE_USERFUNCTION_H #include #include #include #include "core/opcode.h" #include "math/quantity.h" class UserFunction { private: QString m_name; QStringList m_arguments; QString m_expression; QString m_description; public: QVector constants; QStringList identifiers; QVector opcodes; UserFunction(QString name, QStringList arguments, QString expression) : m_name(name), m_arguments(arguments), m_expression(expression) {} UserFunction() {} UserFunction(const QJsonObject & json); QString name() const; QStringList arguments() const; QString expression() const; QString description() const; void setName(const QString & str); void setArguments(const QStringList & args); void setExpression(const QString & expr); void setDescription(const QString & expr); void serialize(QJsonObject & json) const; void deSerialize(const QJsonObject & json); }; #endif // CORE_USERFUNCTION_H deepin-calculator-1.0.2/core/variable.cpp000066400000000000000000000032601325241207700203320ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004, 2005, 2007 Ariya Hidayat // Copyright (C) 2007-2009, 2013, 2014 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "variable.h" Variable::Variable(const QJsonObject &json) { deSerialize(json); } void Variable::serialize(QJsonObject &json) const { json["identifier"] = m_identifier; QJsonObject value; m_value.serialize(value); json["value"] = value; json["type"] = (m_type==UserDefined) ? QStringLiteral("User") : QStringLiteral("BuiltIn"); } void Variable::deSerialize(const QJsonObject &json) { if (json.contains("identifier")) m_identifier = json["identifier"].toString(); if (json.contains("type")) { QString str = json["type"].toString(); m_type = (str=="User") ? UserDefined : BuiltIn; } if (json.contains("value")) m_value = Quantity(json["value"].toObject()); } deepin-calculator-1.0.2/core/variable.h000066400000000000000000000041251325241207700200000ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2004, 2005, 2007 Ariya Hidayat // Copyright (C) 2007-2009, 2013, 2014 @heldercorreia // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef CORE_VARIABLE_H #define CORE_VARIABLE_H #include #include #include #include "math/quantity.h" class Variable { public: enum Type { BuiltIn, UserDefined }; private: QString m_identifier; Quantity m_value; Type m_type; public: Variable() : m_identifier(""), m_value(0), m_type(UserDefined) {} Variable(const QJsonObject & json); Variable(const QString & id, const Quantity & val, Type t = UserDefined) : m_identifier(id), m_value(val), m_type(t) {} Variable(const Variable & other) : m_identifier(other.m_identifier), m_value(other.m_value), m_type(other.m_type) {} Quantity value() const {return m_value;} QString identifier() const {return m_identifier;} Type type() const {return m_type;} void setValue(const Quantity & val) {m_value = val;} void set_identifier(const QString & str) {m_identifier = str;} void set_type(const Type t) {m_type = t;} void serialize(QJsonObject & json) const; void deSerialize(const QJsonObject & json); bool operator==(const Variable& other) const { return m_identifier == other.m_identifier; } }; #endif // CORE_VARIABLE_H deepin-calculator-1.0.2/debian/000077500000000000000000000000001325241207700163325ustar00rootroot00000000000000deepin-calculator-1.0.2/debian/changelog000066400000000000000000000002351325241207700202040ustar00rootroot00000000000000deepin-calculator (0.1-1) unstable; urgency=medium * Initial Release. -- Deepin Packages Builder Wed, 11 Oct 2017 17:38:35 +0800 deepin-calculator-1.0.2/debian/compat000066400000000000000000000000021325241207700175300ustar00rootroot000000000000009 deepin-calculator-1.0.2/debian/control000066400000000000000000000006541325241207700177420ustar00rootroot00000000000000Source: deepin-calculator Section: utils Priority: optional Maintainer: Rekols Build-Depends: debhelper (>= 9),pkg-config, qt5-default, qt5-qmake, libdtkwidget-dev, libqt5svg5-dev, qttools5-dev-tools Standards-Version: 3.9.8 Homepage: http://www.deepin.org Package: deepin-calculator Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Calculator for deepin deepin calculator tool. deepin-calculator-1.0.2/debian/copyright000066400000000000000000000016531325241207700202720ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: deepin-calculator Files: * Copyright: 2017 Deepin Technology Co., Ltd. License: GPL-3+ This package 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 package 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 . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". deepin-calculator-1.0.2/debian/rules000077500000000000000000000003431325241207700174120ustar00rootroot00000000000000#!/usr/bin/make -f export QT_SELECT=5 VERSION ?= $(shell dpkg-parsechangelog -ldebian/changelog -SVersion | awk -F'-' '{print $$1}') %: dh $@ override_dh_auto_configure: dh_auto_configure -- DEFINES+="VERSION=$(VERSION)" deepin-calculator-1.0.2/debian/source/000077500000000000000000000000001325241207700176325ustar00rootroot00000000000000deepin-calculator-1.0.2/debian/source/format000066400000000000000000000000151325241207700210410ustar00rootroot000000000000003.0 (native) deepin-calculator-1.0.2/deepin-calculator.desktop000066400000000000000000000004611325241207700220770ustar00rootroot00000000000000[Desktop Entry] Categories=Utility;Calculator; Comment=Calculator Exec=deepin-calculator Icon=deepin-calculator Name=Deepin Calculator StartupNotify=true TryExec=deepin-calculator Type=Application X-Deepin-ManualID=deepin-calculator # Translations Name[zh_CN]=深度计算器 Comment[zh_CN]=计算工具 deepin-calculator-1.0.2/deepin-calculator.pro000066400000000000000000000073551325241207700212370ustar00rootroot00000000000000###################################################################### # Automatically generated by qmake (3.0) ?? 11? 21 09:24:39 2017 ###################################################################### QT += core gui widgets svg CONFIG += c++11 link_pkgconfig PKGCONFIG += dtkwidget TEMPLATE = app TARGET = deepin-calculator INCLUDEPATH += . # Input HEADERS += core/constants.h \ core/errors.h \ core/evaluator.h \ core/functions.h \ core/numberformatter.h \ core/opcode.h \ core/session.h \ core/sessionhistory.h \ core/settings.h \ core/userfunction.h \ core/variable.h \ math/cmath.h \ math/cnumberparser.h \ math/floatcommon.h \ math/floatconfig.h \ math/floatconst.h \ math/floatconvert.h \ math/floaterf.h \ math/floatexp.h \ math/floatgamma.h \ math/floathmath.h \ math/floatincgamma.h \ math/floatio.h \ math/floatipower.h \ math/floatlog.h \ math/floatlogic.h \ math/floatlong.h \ math/floatnum.h \ math/floatpower.h \ math/floatseries.h \ math/floattrig.h \ math/hmath.h \ math/number.h \ math/quantity.h \ math/rational.h \ math/units.h \ src/backbutton.h \ src/dsettings.h \ src/expressionlist.h \ src/inputedit.h \ src/listview.h \ src/mainwindow.h \ src/textbutton.h \ src/utils.h SOURCES += core/constants.cpp \ core/evaluator.cpp \ core/functions.cpp \ core/numberformatter.cpp \ core/opcode.cpp \ core/session.cpp \ core/sessionhistory.cpp \ core/settings.cpp \ core/userfunction.cpp \ core/variable.cpp \ math/cmath.cpp \ math/cnumberparser.cpp \ math/floatcommon.c \ math/floatconst.c \ math/floatconvert.c \ math/floaterf.c \ math/floatexp.c \ math/floatgamma.c \ math/floathmath.c \ math/floatincgamma.c \ math/floatio.c \ math/floatipower.c \ math/floatlog.c \ math/floatlogic.c \ math/floatlong.c \ math/floatnum.c \ math/floatpower.c \ math/floatseries.c \ math/floattrig.c \ math/hmath.cpp \ math/number.c \ math/quantity.cpp \ math/rational.cpp \ math/units.cpp \ src/backbutton.cpp \ src/dsettings.cpp \ src/expressionlist.cpp \ src/inputedit.cpp \ src/listview.cpp \ src/main.cpp \ src/mainwindow.cpp \ src/textbutton.cpp \ src/utils.cpp RESOURCES += deepin-calculator.qrc isEmpty(BINDIR):BINDIR=/usr/bin isEmpty(APPDIR):APPDIR=/usr/share/applications isEmpty(DSRDIR):DSRDIR=/usr/share/deepin-calculator target.path = $$INSTROOT$$BINDIR desktop.path = $$INSTROOT$$APPDIR translations.path = $$INSTROOT$$DSRDIR/translations icon_files.path = $$PREFIX/share/icons/hicolor/scalable/apps/ icon_files.files = $$PWD/images/deepin-calculator.svg desktop.files = deepin-calculator.desktop manual.path = /usr/share/dman/ manual.files = $$PWD/dman/* # Automating generation .qm files from .ts files !system($$PWD/translations/translate_generation.sh): error("Failed to generate translation") translations.path = /usr/share/deepin-calculator/translations/ translations.files = translations/*.qm INSTALLS += target desktop icon_files manual translationsdeepin-calculator-1.0.2/deepin-calculator.qrc000066400000000000000000000007611325241207700212160ustar00rootroot00000000000000 images/deepin-calculator.svg images/title_icon.svg qss/light.qss qss/dark.qss images/delete_light_normal.svg images/delete_light_hover.svg images/delete_light_press.svg images/delete_dark_normal.svg images/delete_dark_hover.svg images/delete_dark_press.svg deepin-calculator-1.0.2/dman/000077500000000000000000000000001325241207700160275ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/000077500000000000000000000000001325241207700214225ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/common/000077500000000000000000000000001325241207700227125ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/common/deepin-calculator.svg000066400000000000000000000065001325241207700270270ustar00rootroot00000000000000 deepin-calculator Created with Sketch. deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_commoncoperat.svg000066400000000000000000000056761325241207700273270ustar00rootroot00000000000000 ]> deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_commoncoperat_small.svg000066400000000000000000000054071325241207700305070ustar00rootroot00000000000000 ]> deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_optionsetting.svg000066400000000000000000000036771325241207700273660ustar00rootroot00000000000000 选项设置-64px Created with Sketch. deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_optionsetting_small.svg000066400000000000000000000035751325241207700305530ustar00rootroot00000000000000 选项设置-24px Created with Sketch. deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_overview.svg000066400000000000000000000014021325241207700263060ustar00rootroot00000000000000 deepin-calculator-1.0.2/dman/deepin-calculator/common/icon_overview_small.svg000066400000000000000000000015021325241207700274770ustar00rootroot00000000000000 deepin-calculator-1.0.2/dman/deepin-calculator/en_US/000077500000000000000000000000001325241207700224335ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/en_US/icon/000077500000000000000000000000001325241207700233635ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/en_US/icon/delete.svg000066400000000000000000000044241325241207700253520ustar00rootroot00000000000000 image/svg+xml deepin-calculator-1.0.2/dman/deepin-calculator/en_US/icon/main_menu.svg000066400000000000000000000047771325241207700260730ustar00rootroot00000000000000 image/svg+xml img_upload img_upload Created with Sketch. deepin-calculator-1.0.2/dman/deepin-calculator/en_US/icon/tips.svg000066400000000000000000000052441325241207700250700ustar00rootroot00000000000000 deepin-calculator-1.0.2/dman/deepin-calculator/en_US/index.md000066400000000000000000000062501325241207700240670ustar00rootroot00000000000000# Deepin Calculator|../common/deepin-calculator.svg| ## Overview|../common/icon_overview.svg| Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division with keyboard input perfectly matched, as well as symbolic fault-tolerant computing. ![0|calculator](png/calculator.png) ## Common Operations|../common/icon_commoncoperat.svg| ### Symbol Introduction
0~9 Number Key Basic arabic numerals
c Clear One click to clear current contents, double click to clear all.
% Percent sign To input percent sign
![delete](icon/delete.svg) Delete One click to delete a character
+-×÷ Addition, subtraction, multiplication, and division Basic math operator.
. Decimal Point To input decimal point.
() Bracket To input bracket and auto complete left and right bracket.
= Equal Sign To get result
> ![tips](icon/tips.svg): You can select the current line by mouse to edit and copy. ### Symbolic Fault-tolerant Computing Deepin Calculator supports keyboard operation and fault-tolerant computing of special symbols besides normal numbers and operation symbols. - Fault-tolerance processing of multiplication: Input asterisk (*) and letter x to trigger multiplication; - Fault-tolerance processing of subtraction: Input minus (-) and underline (_) to trigger subtraction; - Fault-tolerance processing of bracket symbol: Input open and close brackets to trigger bracket; - Fault-tolerance processing of equal sign: Input = in English and Chinese to trigger equal sign; - Fault-tolerance processing of clear symbol: Press Esc to trigger clearing; - Fault-tolerance processing of delete symbol: Press Backspace to trigger deleting; ## Main Menu|../common/icon_optionsetting.svg| ### Switch Theme The theme of Deepin Calculator is light by default, you can click on **Dark Theme** to swith. 1. On Deepin Calculator interface, click on ![main_menu](icon/main_menu.svg). 2. Select **Dark Theme**. 3. The interface will switch to dark theme. ### Help 1. On Deepin Calculator interface, click on ![main_menu](icon/main_menu.svg). 2. Select **Help**. 3. View the manual. ![1|help](png/help.png) ### About 1. On Deepin Calculator interface, click on ![main_menu](icon/main_menu.svg). 2. Select **About**. 3. View the version description. ![0|about](png/about.png) ### Exit 1. On Deepin Calculator interface, click on ![main_menu](icon/main_menu.svg). 2. Click on **Exit** to exit. deepin-calculator-1.0.2/dman/deepin-calculator/en_US/png/000077500000000000000000000000001325241207700232175ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/en_US/png/about.png000066400000000000000000000607361325241207700250530ustar00rootroot00000000000000PNG  IHDRb IDATx s{~g555]t%tQMG)QH,+%v=ڵeE[h[K-֥BQFQmt4>g~9FU7^3( B}p88w B8\[o1;BP(~d'#|Kw1c} eP( ŏ-aa}}}j ΰa0 `ǠP()a@@GG?o1 `X P(}  @@?g0, 4BP(Er(aq-o.r˭[BP((///ٲeɓ'?:uρ\} 1 ` X $?CЬYġP( ſq'qm 4O>$ @@hnݺ'N0,,++[BP(TQQQ T.  o0,`Q( ' ` `,`BP(e X-˷ `BP(j0 `?2 `Q( ŏO<+6mgϦ,`cwoP(aÆ3+Pݴixw4h5`÷ X0AP(?&-Z`ƌ套^3m4,XO}:_=.0EP(o<,Z3fиqc<͛7'cP `@H& B1ذa۷c% q(Ƙ@P0.P( 7ڶmˁhтEP(( BBP(b¢P( ELX B BP(1aQ( "&, BPĄEP(( BBP(b¢P( ELX B BP(1aQ( "&, BPĄEP(( BBP(b¢P( ELX B BP(1aQ( "&:AD21ƠPBk"DD"";1cb1¿ Du)3/NæbP|#Żհ ҪHcP(A%!.\nφU&5ek^w}J' @k- qP(|GD\ץ7$uyfq08B%WnǴ˨11_ "2/'We̮+"We`DZc X _DH$B$aaA Aq. DD""B/ Hu\@ %6Vp]@  _DAD(u $oADDc X _DDD rP(|IDD5|MD rP(|GD< '" 8(%"k"PEP(pP(|M7APԚBk" , ŏJ*^%  _DP(PoB5D5 EmY B  E9(&Btz^%qԄ5LjE( BP(1Pŀ8O*|1 5r(( E9(&P(jˢP( EL8(&P(jA5|MBQ[ ŏP(>P&B- E9(&P(jˢP( EL8(&P(jA5|MBQ[BP(bA5|MBQ[ &(ZsP(|M_APԖEP(pP(|M's(zpP(|ME͉PBP(bA55'BQ8(&(jAP(DPԜ E`Q( "& _AQs"(uBk.( B 9:A5AQ BQ8(&DP(Bq:,/hH GPmD@D@D@D@D@D@D@DNЫ;@D@D =AD@D@D@D@D@D@ (&   \Cdx뿠U @DG?h 03@@@KA;☵' ~ =R~0CIcȯ^%ŀ8cBk"G +`^_ e6ɰ"a9"(uBk | SkE>\9 (uBk"  5o4TrLAc^Dx h +٫{*/l+^%ŀ8cE5 6VyaYMu"%"(>PP{-6V!}p#q BQXccݠm2ȇ!@~%( ðaE>N?B8, 0s T@A%c%"(>PP{a̧T~|1GP(DPԜ E`Q( "& _AQs"(uBk.( B 9:A5AQ BQ8(&DP(BkAQ#a Y 1`ÉU(j䭝ubR1cP(ǢP1MP ~Ҭ 1Ÿ, /c2e9QԞ0Ny BzaF(Z1Ÿ _1`D\|FJ ~c^w: \|c 1(P1k-@@ @85nOɬ+ RH O+atr@k- 1 @A h$"(GM$!.pp8L8 uD"@ 8A `@ k- c @..  c""8C1c HH$~1x1Xk8 qk-Z1(P1O cZ8K$AD<"11c Z@@ @ 1c 8(d0`Z8"1c XkbBO ocXk1`EDc2`1c 9(fdcA?N01ƠP(BP(b¢P( ELX B BP(1aQ( "&, BPĄEP(( BBP(b¢Py7nOLӹ9RFMzz:_| 9(駟rR]rr2P}r5p 'v"//kC+((^`lٲ27oNΝKjO>̞=?Rff&^{-;v  ҡC 6m^#>>s>}:ׯg̘1(GBq@]v駟&u]f͚]wŝwI-8O?R^^cƌ!++#GrwGDh֬NJR/^LQ(BqW\q> 7TgwNFF~:'Ou]O΀8ڵ+/#*33tNC=D޽ȠgϞԩSbȐ!dddХKFٳg~G%==ӧs0+V`„ ׏6mУG&L@vv6?޽{SXXȺuHOO'=='_3n8tBFF{FMΝ)))o}oߞ5k֠P|EK.4֯_φ 𔗗s?T=\4i&L;{w" B(_䢋.~af̘AINN禛np\uU|G'?aرa>Ơ7-1csΥiӦ\p4lؐYf1vXÇORZZJ޽i޼9|f̘ܹsiڴ)\p 6d֬Y;O||<ÇӨQ#Ə4h5kp2o<7obԩ\r%TTTP]QQ]w3gΤu4k֌f͚P|?X $@C "J~l> B2j(9#GJ(zK? 䩧QFI(իWKԮ]@\ו~I(ݻw'77WB 0@wK(SJTEE\uU GQFI(:Hff(Q-&@C HEz)))k1ILL /ijxbӹsg9r$Eq({.'*==&Myf$77OJJ ZGfhРUUU瓓Cvl۶y7qU~}~(͚5ATUUONNڵóm6%KФInկ~;[ҥ 9('%%ƍӇgÆ xn6n6Ku/##9P( Hz!"c8g}uQUUEur 7oZKv8R}Yy֭[GUUչlٲm۶k׮Z6nzBqh EUVVcǎx"ƌѣ3tP7oBՉpjaÆڵkС3yd&MDV; )))SdFDc)u9ɓ'3i$ZjwAFFIIIL2%Kp(@HHH@84?gwN(“5khӦ g9Cٸq#[f -Zp 4YfO裏r0gOӱcGL¡jՊuW_Ѿ}{'۷s(gOӱcGLBuOVp 6.@H$qBQ;#8wy'Q>{wR۹s'x glݺꊋʢ7uV^|Eѣ2dk׮/3 ;;P(֭[9noһwo:vH^^WfΜ9tޝL:K.aÆQ\\̼yسg2d֮]_gAvv6>P[8v}w'x"͛7箻gŊ׿f޼yjՊUVe:vȸqP(jǢPPNNo66mSN|,^ÇS]bb"s[nA,^%KD7n7&w?0:t'-";;.^zQݐ!C8q";ww!99o#mذa;\y4oޜ/?r)g„ ?alذ;3JJJ cƌ}vL˖-~L8u2e s̡L:C0aǏGD={66l;䷿-{G4h[la…<[7dĈdee`<ƍcܹ$%%PԎ `@@#D8233:t(sO?4 1t pBP(1aQ( "&, BPĄ `@@#DP(f @.. BP(b¢P( ELX B BP(1aQ( "&, BPĄEP(( BBP(b¢P( ELX:fTW\\̸qXj?>G}#)2n8DD3g&L[oW^ADP(6ٳ'˖-'>#11;Chٲ%p#SRRR|,ZѣG3ǓBT Bz$xA5jD۶myٰa^z)T'/G.oi4jUnON{? Aʁލ);޿}vœy%xmv#u:{RvGቯٖWIRVBC·e ү7-džԦzAj4sur9Zi?Y VpP]|&P=˟mK \BO o*V[rT#i7 H ז9\S%BΪ@3 (UB6A4p45M?4klCW(.:6R ((y5MD$Jp#8%TgV§ jb}~F6)Z?. y=cE3ZyuJve]S˶)>#P(m o 9pd)ɻk5|c-M ē^iS^NZAene}WG!W-yT~GVMS ű͢PV\f؞&MJ$jqV!jbۚmx0Dŷ Ql6R5d]] ZcEv '#Gqp%?OImHK+;t2x9pE{CZ"$N'm+p8Zuj皓 W7%Bbtڶ8UV.Gvu=4g^]W(ZZvhUV(d @+(?^BqpIˢPuIyD]Xfx271wsn.G5``['sc3|?Z@ѻa.* ])fﯮۄ>a*[3%岝1Wai2j-P3a|6Ch:z7rᗕbM.fUD$_~ʍaO *eQN*%k+:,xpNf~Pg%,~Ǩ?3fr EXnHx[UTOidyui9++HKo"ﭪD\4H•X9+݅Vm㙳IK|uܢCSȥCKL󒙻2{rhҸ$x8_\H>浻 &VLmUTT ?քi?-8חW]2N-oEPĖE8t'(ʍa_]AqpD.-dz0sNghxr" W Ldr< 3+8xzI;WP\. n8'7?RXtRV5ԶAFOdDD}RNva'5qAn^v!-zy=o"3?(.O\;8Yq '.и'}Y9yR?'9M7AwK5IWpVxZ^xz&}Wԧ]A-EdV!qO"SaG/*~SC:gi8;lr9s?7rؑJc`pxɬE~Z?^•,\YnoGK$CT&vVfUV!lqٲs򱖽*ÐZe 4oJo`W+Q`*ٲ带Mlս]v乴iP]F El9(1qΩ,ZUI0]^~hd"*99x$sS.Oq4HbaS MOP/0W< -Oge|Ke+P\.K0x "DJ =܄`oK]3hD!+7 Nq}˯g'BQ0م.=?Z̆]..k?0 K?ښmnXQgd/(aeD}f2_"KU2%|ɯjs", EL >%gvq}|J<Oυ% Cմ[ qpΩxJ!$'8®hjwg#Vn 95UY%w)*OqE3{wG+6mr^&_߀GݼY9N2 @A h$"(;\s?fHB3t pBqdkUe OZU&vV1fr6Gh~.qܺz#vq|6yϠsdRQNҾ|4~>,S y2tU@k^@QDE˼ 7 WAs5mZSW+AW6wK-o驴cѼdbXIjM4Yr2gpSmq#MOeo 텻Faro2NLюWvtB*I+Snd&VqnbV=U+?Nw[YGxlX;6v塡^BJ>YډGxm_#gm{hǡD.FF-Iph3†.jnU Fѭ~7ue-g֙t?:m㟇çwyzO.n`<6/KcަZ}҉ntps#*{m_wdxw1e XQA3M?zާMN43b@ a&jz#}odfoF6?Ktq0o.QiE\6<|]`O~3;uG[˛>n%{sC;1wE7k]n2ݓ[=9+mm}t%U'f:kOvto0t/[;9 = ?=~r>?2 /^!8Ѓ?_vңkilu[=7w0ҵw~Fyz@]_vpzt1r+= hd߉fJ bٛU{ʹT W.\v M`` tޝh^|E\O-//QFCݻ{w޽{ӧO}Qe…̞=#>>[r=N?+))L/_Nzz:?xnO "''ֲi&~f̘%K}0g\jG̝;;;3]v;|0O=l, =d|g/2uTyuFpp0]vv6C wq)Z:<&L ((_0{lpIMM駟+VAPP׳az-/^d3aٹs':JPP֭#$$e˖.==8q"!!!NK 2޽{ǩShiɒ%ߏngӦM_]||<3g䮻"44%KHCpB&Mׯ=555T\\ &..>Tbbb۷/fBDНjjj0L̞=ݚ5k"$$)SPYYIKdff2x`vM]]'N$$$P3~x#//8q" >"\?~<őnɒ%ߏnѣG _'55lL&[lj2{l0`K.tbZѣs;;d׮]\˚5kW^̘1݊+ ((diѳgObcclDGGٽ{7'O&,,o 2e _} Ġ;pqqqL&8y$lRRRx'ٳ'Ri큛@7L| v]\\"ݻw9p :T˥VF!8p@*R[[+#F_]% @V\)JϞ=Tl6.++KСC[|=Zv O?TT.\ NSdڴi[`̚5Kt#G~Z***/&5k̟?_\̙#b ѝ;wNYF%6m]rr[N\F)ϗz9tKN>- )))RTT$bHFFlٲEbccnKUUJKrq:&ӦMw/^nݺIII455E`5k,L8Q\" k֬eر[`DDDHyyl60a̟?_tE222Dw}ƍpHFFWN+-- .锴46m,$''KssJxx.66V.\(MMMK@@߿_8p@*R[[+#F_]tΝ*innQFɦMŋҭ[7)))&9~v >Htos=.??_e߾}&'O4iL:UZ2Ͳgq_l"bۥJ Ew}ƍpHFFWN{gdرR[[+*/}'7n!ҷo_믥[nRRR"MMMrqeeeĉ.ʕ+eĉh"ILL29}ݲqFYr<(={Rqo> cǎIEE|W;wTUUIss5J6m$:"R^^.&In*rIљfٳg/ .]]AA466JiiSΝ;'nM Dwe1LcZzj&YYY K,/Jss}n@g&= / "Frrr(**⮻Bp88{,q]ws8={{]tt4:uرcFc6хyf, IDATihD4%//S]]M]]!!!]???N'۶mcϞ=l6ʨ:?ڵki߾=f;?dtуb6Yl&L %%X~=.]øqxINNZ0X,BCCywp1tݘ1cX~=V+9sŋknnΝ;㒗멮\ˋ[o8}4omڴaԨQtԉ>#뮻9Ξ=d۶mٳFYYt҅ƍǃ>Hrr2lٲcƍ2l0BCCM4zl6l2&L@JJ wV|Μ9ŋ577S^^NΝq9|0&M___bbbYV9s /F܌1117|d\III'66ksƏONNcǎEwSN;v#F˰a߿?:???N'۶mcϞ=l6ʨcǎEw7}UTTn:N8nSQQAϞ=qw1HHH@7yd.]ʙ3g`ʃ_""~FɪUp`FɪUpgZl6\l6ђ7DwF^z駟qmFdd$*ٸE4555・۷oϣ>В%Ӊitԉ $775kꫯRRR?ζmۈW_%;;wF͛7dž xطo-mw^^^.6 ͆itwW^\KII ?8۶m#22W_}l\q'" \ -#GdժU۶mo6|<裈F͛7dž xطoIII9sΑڵk+Wti-iFtf>^|EtwW^|A4\F#:A{nzꅻ͛7dž xطojFMHNNחv;N'bplh;۷oϣ>NDMpHKK.LڶmKHH"BKvk4 _2@6Rv̙38q";v$66{'@AAEEEƲw^>(((7|ʶmۨӦM_f\tb>L}}=Nپ};-ү_?֮]KUUҵkWΞ=PQQi///ڶmɓ'9t.>>>bh߾=dڵXV'&&﫰bF͜9s8rq:P^^i#GҥKO>TTT[oa6qCdd$/TTT~t:񡼼۷oAcc#~!eee޽{Ohhh"m۶LHHݺucƌKYYuuuرڻ˽˵̘1%KKJJ"33ݩSqIJJ"33֭[{RVVOeӦM1j(~V+۴i.yyy5%>>[KJJ"33;vDff&?3f`ɒ%\ϟginn&//QFq=IIIdff]D 4 rK/!",Y˗/Ko>vAk1cQQQx q1cQQQhFK"’%K|2?R{9\˜7o?wv؁ˌ3*,,yq=3f **2c P&SL᫯"!!}ӻwo"""ضm%%%R[[@*++&>>d @||<_~%lINNf_Z̞=0 ҥKq:XVXn!!!̚5T1Llٲ;v`6իC Ӹs8L<0nv,XNDXp!aaaDEEg\8q" >"\aÆ [,^Dqq1;pqqqL&8y$ 2i$߿?ƍ\ϒ%K'((ٳIKK%55~L"## gLW_}EBB111XVXn!!!,[b &""{jeلd21{l>SO=j2{l0`K.t'55ˬYKvv6 &Я_?شiqqqۗIII ֢+++#00J\HHHٳ9|0O= 2i$N~xǨtrrr8p8zIll,6l B޽ԩS|礦db˖-L0 nv܉.;;C=/,cƌb ٲeƊn*),,b |L&ٱcXVYzDEEf, Cn2zh݀M@{- oܽΝ;y)))K.-]t!""ctftᔔҩSXt)C%==J\`0JII Ç3a|}} "&&;F.]X,mۖZbرddd۲e III3XV&L@NN={ݱc#!!v1ydJKK9s :f3pJJJ-07tP:Dxx8SNeÆ hFv\v;v;.vݎ;Ӊitԉ2sLv؁`X8~8.]JMM |ǴkAD0  \DMp1vk4 7Db4ټy3/Geףi."t SG}t"aqt:4 ooo܉Ӷm[yzzND4 w6 ͆i|qϟOnn.ӧOGDAKNMy{{NDhiԩDEEG~zDooo܉:A4\F#-ȵ$%%go{qHnn.)))YSns-Ɲ[`7חSNЀÇcۙ2e ?};vÃBtv]EE;wj~z郯/ v܉je___ ƛoIYY.\`֭ 2k444ڵ+#$$/wuuux{{iաbQYYΝ;q4h.՜;wr->>>bٰf*++پ}; [L&׳j*fϞ*9Bdd$K.vٳg***8x oNee%_}999ft:ucظq#.w}7t.]@qq1 6lo&eee\p[2djǟ'~;Aaa!]vq->>>444P\\LCC-}'>} z-f3eTTT{QSSÇtCyy9۷oח@cc#.7tdڵXV'&&﫾cظq#ǠAxwܹs6o̯_#Gӧ9s&'xgy{w~)L&1c,Zwf owe;v˗r72`;=Cbb"deȑxyyƮ]x0`}SN3wӧO~nȑ$&&r}Ohh(.3gۛ(ONLL #Cxx8.\Clذ+Vݻٰa\ի;w.1i$L&?06~1bFMRR#F@O3p=p->,/"wy'~~~x{{{'޽;Æ #..|L&F"66'$((X,$''s=_|%%%cxzzh"~a6),,ۛL&F"66RPPӧOl6ӵkW|IKΝYv-+V̝;^z#Hbb"Ѹ9///صkVZř3g۷/gfٲe}=쳼y2sLbR.]XlO?4<==$Ν;GRR-]x$zų>ŋqסC6l+glذOOOѣ8p_+ 0Fx@ODN&--Rvv6iii /$IDATx |oA[Ji!*(N'*cȘmD'*"r+ )ʍ-^M %irشؐ~yy~'icX,*a?_ P3Jh:Mbj)ᲅ4\oVoARLX*SG|WD}m@E Q5A-.V\ cZ4.ƵhPh@aDc-:1f' \4gLP6mfLo4oN6-P9άUO<2Sg|lejR=Zt& i{M5C0dawϴVT^f#zjժ=ZQJJʗIII#^hTTdFNN**+˕~1=g䒯e̬Vkx.z{ t˞Ί_\昙65C)W_(m\EYT_3T?Au;}6]T^שcwNكl>DFH30UCNjRt}'G@@v{v9CZV5m^NIZ.mڵ8qu7sۄ ^WPˤh3SoK~@fq#F\;/[ou%կsEzfVP}2APVTwTNn喂.\cll6~EП3C%G5~XB;sbz3T*x+G8!s?3K1c\Йjn4}t9P/Qgϥ:ku/W^)ShԨQ +X B1/oosGR {N|̃D{)*@vAuϢ aKAmiqC۲oA߷kgRc]ܛcn!a9>cr)x6y] qnQPVf.suǐܛc3;n} ,%y.VP/˦! *TA @PA @PAT @P*T *A @PA @P*T @P*T *A @PA @P*T @P*TA *A @PAT @P*T @P*TA *A @PAT @P*T *TA *A @PAT @P*T *TA @PA @PAT @P*T *TA @PA @P Ps2Rp!ZV-F#Ɩ\} &A-=z,-Zv>îdkVޤIv"V?oL^9\]{[5剱yTG6g'Oր+ R޾狓65T5W&+б};M:| s@'U=rSZUjQ~W=~}mbcv TlՇ1ͬ-R{Nl?(M6;jZ#\ uVk}ZH_3ѭUsvqFI& u^>s 8Ӧ-nAs&6=c(uZxЦFۋb16rǕ?⫩Ru4N9C\!ݫ;;:tsss裏j۶m?+a _;-G]ih1XA52 nݫR>&;Gԇ s.OS=;uСƍWoVO<?I &vL4mumC" %:&Ug9vQ,4IV'Ж{aΚ5K/~mڴѳ>{W!!!=z43-j6!U+9:c0 n5VS흵JP럫tZ7ږ|F?PEk5`;Uc{鎩;?ӦMSn Ωn߾s(:1r鵹M(]VP-! ]=?(uA륧]t߃WhQmkbPz6ոN^Ԧm4hP9To~wL,ݳ 6,_}U5oޜu6gNB ̥=oTkG/~FCnjW e{Kn|"qũChB5Eѱ sWyǹJ*۷Nu:}tUVM|S~ETPi{nPOPҔ*Gn1+>zR#hz{6f|ߙ1ԫۜ JHtYp#ZծOT)?i*?.?yËm)<Zm뽯 Kx}3o[?&ϳΥN4K*լ 'tN=R3͟9O_oZd*לgEPVϤN3YXψj₩j6飑:gR v^m*==e36džf[aq涑233@Ce?MфQUC-]IOJ0CoޘZ9mᝣdF+&f-tS?ݐ3Ʀq 0C=s@hk==R;}jnǪ,}JQ Q3"C[Opj:ngU<te\1㻵E[6?-Q;].[Iq1PeuZ5_-Z?[RbL7T]^o׋u-:ӡ{Wt wSwZٻJ#2V1vݯnѾ݇ǫ*2Ǵb4o47)F;4FpUUvEG8ەN c~j-:jb o>5nzvm[K1оo/OF~jEPKئק)8ҪZۮ{P&s8YiN:f7[Y,uoc?m=ө'm?. >^gnٮԅ/S'ږgff*22ͦҴe \^?tœe ծ|M#XÒ~F}mنTq;z4D' Y#|,))B;f*[qێR.2Ae]A *A @PAT @P*T @P*TA8?!cČ!cT @P*T *TA @PA @PAIPEGǾи''jcT;[׾'k us-~}:of\[vS2Bjtk}vDpsN Yx<te*Zޤv #gQXFߘXo:Z=IѲ(*A zgc]u6}jfTU-z]5/wr&7C}j2&]@'i+-q` ,25#SHEG2-!I7Yut=)[khhw!J:tIyuirh\UӸs*g<ݹY',  E_foIK 5aj-"t4'0[ݬyF3L ԕm!t,nX3_kZ_-aG<7Lsι3mBAyRs)?ߌ=T!txdպ̪U)ǔmHі_yGNYX5 =; S( l'_M"UZB7W FXDXOf,Ђ=]4n'#U(gt5{ j^*EO]ۢN}GOKiϾ}uZQDU+r9!W*J] )jj&A8OPQZ6].מe+5ʷ*4'W$N%=Z 3>jiD|LvKbT Y ~*xl-08sP]ff"##Ɛ1 X2\~{szl'yB- @P*T @P*TA *A @P@Eϝo?2!A-{yN2!K~A *A @PAT @P*T *T@qD+&eoA<~1m^f/]?)˚tV!:0B%;I_ΞwhJJV=oU6l#c>kh[ EHjW;[լkw ]U]Z>w?_yFwurP-zﹱZl4R7Gr{fJk_3ެXvUϫ,-XI"y@apwUU{Ly{Fs ;CSokc۳-O7m;2pm*1/ϱjWz׫6 (ƚRlj%<|;4~CLK'!WfkuT~Ò22k okEF ]Ӣ_ֳfY1jԵG<i5~.kTu).ҪS~7i}zz[TTG2ds`ۚKku nar\VEWS}4 MUB7Gf/B È3 Ueff*22` CnwMң5>f*[q_-9 7f0CخoW %T @P*T *A @PA @P]Oo?2!A-N2a ;ng XA @P*T @P*T *A @PADr,{/>ݮ^Pk8xDqlO}LSz{CGj  A-_U]Te,D9.ȹOsޝ`w ?@vӒ)ӎ\=Z?Ι5Yu3OԫߝzrjLeHs4w:;Y"xdf<,׷ڰ&~Vjjӡ5k8dLujR=muNɹڴl(*A-~ҁ#Ԫy Z#{{0.ڸ%K jeXQ[+@ '(*&Z"dž*u:>iŅRhOEIuk){T^m߫],te`Yl0<>HP/NePй;h=ȌlrpR(eUx?b`QXEi_ Z&Oְ/,`g~'J2dW).BPm+vu>XBJuu+8ڙ^gnTdd$cs--CB[6cVuYͫ&0///O c}ϛYRf>ԧ[·9{Kn7 5 #LPJ3Ӝ%~UZz י]{Zlf@(TW٨Ht=9*F٪Pі*rhP#VEPTH4]6Z*)M^>T_Qr@E |(6BkVJLTQ}PO5+?0J Pjj*M_y.hNIENDB`deepin-calculator-1.0.2/dman/deepin-calculator/en_US/png/help.png000066400000000000000000000466641325241207700246750ustar00rootroot00000000000000PNG  IHDRjk6tEXtSoftwareAdobe ImageReadyqe<(iTXtXML:com.adobe.xmp hjJ"IDATx|eQR()zGE`A S;ջ弪罾wEP7M I%wg e'$8&Nfٙ? ǒ*//ABxΘ1vh W|X=ΔX9:][ۯ#ڦM=~޺'D֜۝OSuҭj~=BZ5=ⶭ7 ٍj <,FO΅-:7#ќ'*Z|~$oZU7p¨QW_}Eiʔ)Z|y 7+Vw֌:},Xyx`i6jW*ޣuY>?Tմ"TjW/GfZ+0$\:ф{iwhOW6ڨG7v = ?Z[haaۓ,kPNNc_Fqv_ޫLl 3N=٣J@s ?T~\4"ڵSRRR4:y'hrM-͆6gHngUچ/W4W-t-m9p(tYtxVr׻Z|}2ݞy*xuEiAm[[ fn8o״qٚlY^/Ūf=hƤx%N+5hиFONXX[ǎ+y:|JϗkvkmJ:) ho=}߿٫7kG)VVuÔ}8T\Ȗ_Wutw1Jbbuܷ"xeH5ޮHui֝#8Vq >[Xm3-M ѸUjwFj޽ھbfPE~jSkLZT}KJ[7P]IWuy}h5{ZVžMZW)ɼßַ/^T, Իװ=q\{Ӣ}PJN>^ݏ~9tMI3ҭzwէIy9V؍jP3Oю0{Qzimh ̃JZLմm@i: EyJ3ђD8 }D,~J7em[%<5D/4=:p졾Y>zbj=:ns 9YsjqRI;zrrt>OLM,=4#%ګ^G:E BtۈZ{ K |rkN%D9n;:ϥn@cT5k4i$ר vjuͳlٲj[}$^^QVsRbuRZ j6P^:h?*s"uR}r(#=m %Vp x¯l5XRkcdtUeuT)ڼ1.A:5H)+uF];+su8jB֜88}f=g"j evi-}*RڷA=K|zLzL u\@p\M޽e[^-K3oz~@gjEbk#ҟnO=׶^ͼupΟ{w(}u^5@O˶W?o!=vV*섛X[i՝"E߬d#zw)+WGjǚ]8@W_;C/L7:Yš۝s?vLDԺ{- Y:Bںjmf=߭Pl'+=YoW£ڻcG5vW븽gfᵛ4f0Q^qg5kDMyh_LkW||4rׯԎn?܎.6@kꫯ֝wީYfRh`PW R8^;7@Wuc*I}N(aM\ס̓7kV>hYժOTbr4 ыtc#Oik[(xzt}_~E 28*4|:f4W`@d5_~7=3tK~fs5ϖJ|z:Q\rTsV*CaKdĺޑP@)BdЁ5Zm=KksK_@O'ԚUpdžmn>yi_ 0<v9eՇzm(N0C7*th߰z?j+F7Gx3z2Af26'ogjWV/ZL\î"5˕鰪q뙥K7)\s:l3]{O>y-^Xw='*88q/ ~u`A?7ϙg,ԩST/MԡKҔiIڧ, umkuRaY(ЮŋwE=//*,ML)tZP1y0;J)5.Azx;Ͽ^3{2nkW3r M1* T欝ixpem8.׫tcҍ{f{ U(Ra- 680ѠuC7ݲ\\+wGfkuOW6AmtXs_}l|6L1#5{ߺƞKŋ˟l׉3;rL&ѵ=VtT͸>/,RҙE'jTk:&7>K35ofqçkӆ,/Z_+BztLWoF S^̒,ERY/ݭe:K֚2-{;<^5}m whği]7·S#o>xvAk:?Z{~1hAf\OyZ%1R'K(W^yEC ѣ5m440={׿BBB~=AJG-1[~~?ҶWث9oQ>1E9e~tk֎Q,; rخWV/TMs4tTvzKKR %7$[-uӾE:{utەS7=#ڪi^4. 68-._,j sr րRbvƏpi/"!b⪋R4qyIKƟ?;C*.*gceU<-3kگז90Y*JQQen+tX_qnz뗛+zۡpN5*]Yq_y}hgƮK[}["gOsr[Ӯd6Vr]ηqQM%~Xi6 eo[sFw֡ݧ5k+F^uu`3Z:K_Xϕ=@g*]7J?|O-,@ 3\F.ݩݎ.4N=''G?5vX-Z l2ow`u(-)un>MdҮk9YrV~ﳫ{Z[1 @-1E8 1lee)*C7U}=ު[,ǏS?c%xՃv#Wg-\~Y^/@e>[ eW~ݔq{`8iɦ v~A_hE}\Nvvϟ;NÃ_+CuTNu]KCoO[YUX ~,6'Z;OAU_ͼm$4Mx>}w}7_QyR!4V o^l]5y cK3Vk%gs];Y#WS8wڸngjRvZϷqJlWNVY+.7Z;䰅kvnUC"]ysdjÒ 쨈P/_zϵ*H>Z@cpvC SY_utN78gQT-x39sӽ=U}FBCW=ZtR6[N~Fu?at-ݩ^0W^eEG2ׯm~z;aiuV - ߹cmGSo^^ҊY?)~:;c{sArucU`9DKh/!nnpz.I7-铢st᣾ aV=ӱjiѶY󴷨fw?xY1TmټT?Q%JQ\VK]l3Fãp;.hT}Uy^_\?A-][:Eq pVbC;)"{˒xRXvXBN?skq5yvS.?|7?iO/qV$k3XZ co~?nW1^A>ʍ&/P?yZO5^{yu:}'UmH׏+Pֲe[ ۰SGPqunWCi:`FO#S/d xbk6W?ֵ;[=Wb}wjlj*ڳH߬]iblZw^}*Q7 )jWfi1=R7=M-HZ/>jW_߿nܺKŁ1:k߼5}S|TupWn˼m?iKTmMbھZRT Љ'Ժuk_h`|XUW#g ~MZqTFz{4e3.XկT4i`g]5 KP[{YUܿ^|Q%|~B (te`Oͷ{ǩϑc;Kõ)H{W,ЎשEZZ]PC;VP;RmsmZ|.:fRt0EEE1ZP6mwRr1L;"k,ġ!Ko~Y{*{rR_g׫Y:Hy`a1F3+=%F8NSq cpBW\/Ɠ:f*FJ4@upJ'Jz[IˎuΧŁ1dX`` 'YC[INuΫt5% 돗;6T YU!XJ/X_]I =#cS[P6.9"eA.^"y]MuHd>V 8v|SV,Vhŭ Vo^,_> Δ b0~:'[ɳt6Ȯ *, SaT\frXYM 0EpLS0EpLS0EpLS0EpLS0EpLSGMf˚ cVߞ0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLSPڹs< effK͛7Wppt6mڰ09L1V4Nc~m޼YOrވ]jѢ+ZSaT\fr(..ʕ+]W'U:v￟ "͝;W5mݦHV p. #4X~=+h-[VPPPٳgPX@ ݸ%O>3fl642(ө8 Çeϵo^-[tUn>,… 5c 4lP? 90 ׎;p8=f܆pw+,,nΐ\nC3nP3{}/#_ϲ:P{k\h`00O:UJ@ շju*Td xJwM6uPea.JM[U^NNMϯc NRR+޽{?`xxTaFFFnj>а* Д)Sj<^^>Zhhya޼y~*r3];+pI.Wqc8HVP/^Kp^v-[7}ށ w1lR6o#4HNN}ݧr^a뢓cԜ9s#G*,,\uֹF';\AݙРI&%cejc߾}z뭷LCCj̘1(tMZzW -5?hʕnԤI* h\-5c(#Gm`46*@ QϞ=լY3V2P~Zj VehmeS\\oVQQQno۶nVWP600Yoٲ ,=zu%K\øqԼysV:P&<0 lިh0{l߿2ƭ g:o3a_|l&bccu]w)44p?T~~'*̜9SV;Ar˭ #Ot="@=@HT[?РCOZbo`pEEE7o .3Z@#d\o'>>8GCݻ]?1#Dooom 111q;oFF6mK=!..SŢs}9cąS*""^{kYFH\.\0nFl:t5AMθZk4e_r{[ɢQnFY@cϺ}ܸ-cƸ%a֭Z'B~LQ=cC6\ ) 2c\iqw5a T&MUVդp2n)Zҟтh޽gϞrN  00ŋ믿fE $8hڴia???>4ZF낯plѠM7o}=z4+qs1ajjFjèظU:|<-ZD5yd}z7\¾}hѢ6 qo4l6Zl9cdTjjTdthN^\h'j뮻tR#UV 8@vq͙3Gv8F]v$1Z'$&&jmB0#P\`?W~~~ _jƌ(ڵk].CCC-1ilݺ5+@ ̚5ի <7#А N:FU@g'_Vp:;.?q ̙35|4"8K;vp$ˋ>w}4//ղ ))Iǎ37[n eQzgMDBp$<==~sӼy\a;6m"8U.]tO>q|LLkGDjph03^l׮YI -H n toP6mnp=Kpvf͚#Gj̘1|#P5n+\,ܪ`FFh'N0}yd˄:aTO:UjaYhhEhqfC&W+WtG+2!8ԉ=z>7|:tƈ ۶m͛M{\ˈ[ w@PPy/RX^vvv~{=uMaaaqi`ƐjLc!Ca.#Fl6n&}n7F^سgkǻ\>ܪ>NAɲR2.3\}l@#uuiܸqEcǎՄ XI*3fΝ;|9WI3ep >\۷ײevhG~Ph,s"_{u`{ҒjhOGw nw7$KK]u/է&/Og<qTHhՑ;]C=YM ;݆tlRESx1 8ٻHOt֫${}9GӚjl[؜2KX9KUqmšQԎ flx)@-}㣕Xh=jy|u&BQc';w4בּ7 Ҿj8 -ゥ=5)vv"_>ONZY1)'TԬ:FvTsk{C_nWkbP^U˾O+^Ҝ0{ԿYUQڨuxzwIuܵ {M|L9+ڹ~=u2n[ncڹ]ƦWOkwZcGQsv~0LZ7):-:k4]v\1hnЄ>࿭eOno5[g!i^cnԸ-\jrkwy}!kbsnRBj,:Zպš^w>"8+ D(쮐\q6+*>Ey;uvvySuquLVdiX=[/͍SǛ~i@@ sהּۂ(Ymmt~R^d=O1 T,Y;TwyQTVK6JW{)m ˞Tڡ>[DG{uW}j슪~-t䔾hN'ާ[qygs76];HjrIz8+JMwl7n1^ɧu(*}BM&ZWH7"x-~qʢe3'E{)&ok s))&J6TieꬭyVy'sȐxy ʰ_~{}յW$&(&P)ώYpt9;}šQ,óBOU/RѲjZHxV=ㅲOVARIQJJ:"{R=)Dtmtʙ2;Sv|˧V_;+ꎣYeZdyjspTu^фC&ew}<*_y-wh=hUxPx\V5kNq;g;UMR9~2mPaSVv܎z;npehNlڗW,pҝ=TZh֥"s@^1]\.͚*3v&u"TJդ)\~?lՁ S&-ԩ$i*U a{@Js_IU|u-.Y)5ΑGE/y|9,k¾[:ڃJSiletN޲dVS/A5gs S,aA,rb8nU@;$h[tLai+nqK 7Pψ&Iث1 ^%=&[uQdC'+)KDˮalAĮq[BfUXx99:\h-ܧ 6*6WtRKjӡvչ]J9q?*6܆]{3$Ȯj/z;ť@y٦ETfuq['TXb+ :7PFA(_O5m<~f*wJqNU1[ 4(8@vN7>ׇ٥۪yQRt4:OE#ۗ[{wQZX(ay@%ަ/MWޝڻ@R*>XOUϫXv-aRrCB_A{Y?Z}D::Ks,G}%,l: B PpnO+GN]mOxy=.~jT￯;vAk_U.+%ǩ{{0R6 qho}EGܦr/_O> Y>qqZ=k qJ$4FmpVRvGڅ uU'?U3+Fi[VSٹܕf7hYYq[WiUjPNɪRղ+k(S<&ѶJkp5ݨ> 5Z!!ZM6Wfh_hC5( .w}[CI}Lw4wѡamtr׏JȶEպeXiUg-@]񊜬_=S.C7L͐ef^^~Am#?RWS^v- 6QҷdcbPIֶ2gd˼v{ piiϜhNln=ߔ5P׬VkG~TX:4UpS}H 0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpLS0EpL4nv -`3'r,zށd_U!z Tn:c7T 2?48#y~='$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8p$H @$I8ұp0[qe8ߞ`Z NGUx:iK8vs?# [qXƇ/n)|üx㊃iXLaq_Vxsf9loj_^^tuufxwonn~en|aHpݏfq8p>p=M"<m\t]tpdĂ9ƅ_`ehp`9ǯ#ѠVp:`< _Wq;fqaւt#t$ c < 0?p! p`XqODiJ8N7 ꃊZ8XƃCDN/ W>* k@43)y ׾`}0q߶b 0kIENDB`deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/000077500000000000000000000000001325241207700224235ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/icon/000077500000000000000000000000001325241207700233535ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/icon/delete.svg000066400000000000000000000044241325241207700253420ustar00rootroot00000000000000 image/svg+xml deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/icon/icon_menu.svg000066400000000000000000000047771325241207700260670ustar00rootroot00000000000000 image/svg+xml img_upload img_upload Created with Sketch. deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/icon/tips.svg000066400000000000000000000067041325241207700250620ustar00rootroot00000000000000 deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/index.md000066400000000000000000000067761325241207700240740ustar00rootroot00000000000000# 深度计算器|../common/deepin-calculator.svg| ## 概述|../common/icon_overview.svg| 深度计算器是一款简单易用的桌面计算器,支持加减乘除运算。完美支持键盘输入,在键盘输入时还支持符号容错,最多可以显示三行计算结果。 ![0|main](png/main.png) ## 操作介绍|../common/icon_commoncoperat.svg| ### 界面符号介绍
0~9 数字键 基本阿拉伯数字。
c 清除 点击一次清除当前的表达式内容,连续按两次清空所有表达式历史。
% 百分号 用来输入百分号。
![delete](icon/delete.svg) 删除 点击一次向前删除一个字符。
+-×÷ 加减乘除 基本数学运算符,用来进行加法、减法、乘法、除法运算。
. 小数点 用来输入小数点。
() 括号 用来输入括号,左右括号自动补全。
= 等于 用来得出计算结果。
> ![tips](icon/tips.svg):您可以使用鼠标选择当前输入行,进行修改或复制操作。 ### 数学符号容错 深度计算器支持键盘操作,除了常规的数字和运算符支持之外,还支持数学符号容错功能,让你在键盘输入表达式时,键盘的中英文状态和大小写状态,都不会影响输入表达式。 另外还支持一些特殊的符号容错: - 乘法符号容错处理:用户输入 * (星号)、x (字母x)都会触发乘法符号激活; - 减法符号容错处理:输入 - (减号)、_ (下划线)都会触发减法符号激活; - 括号符号容错处理:输入 左圆括号、右圆括号都会触发括号符号激活; - 清除符号容错处理:输入 Esc 符号触发清除符号激活; - 删除符号容错处理:输入 Backspace 符号触发删除符号激活; ## 主菜单|../common/icon_optionsetting.svg| ### 切换主题 您可以点击帮助获取深度计算器的帮助手册,通过帮助进一步让您了解和使用深度计算器。 1. 在深度计算器界面,点击 ![icon_menu](icon/icon_menu.svg)。 2. 点击 **深色主题/浅色主题**,来切换主题颜色。 ### 帮助 您可以点击帮助获取深度计算器的帮助手册,通过帮助进一步让您了解和使用深度计算器。 1. 在深度计算器界面,点击 ![icon_menu](icon/icon_menu.svg)。 2. 点击 **帮助**。 3. 查看关于深度计算器的帮助手册。 ![1|help](png/help.png) ### 关于 您可以点击关于查看深度计算器的版本介绍。 1. 在深度计算器界面,点击 ![icon_menu](icon/icon_menu.svg)。 2. 点击 **关于**。 3. 查看关于深度计算器的版本和介绍。 ![0|about](png/about.png) ### 退出 您可以进入菜单栏点击退出深度计算器。 1. 在深度计算器界面,点击 ![icon_menu](icon/icon_menu.svg)。 2. 点击 **退出**。 deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/png/000077500000000000000000000000001325241207700232075ustar00rootroot00000000000000deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/png/about.png000066400000000000000000000543151325241207700250370ustar00rootroot00000000000000PNG  IHDRi$, IDATx`UsA !%a(,A{UܵZ*"*h`AE(EF02:$dH⸇C B\ΰ+BP(J3lg(cؙAP(agBa;a;g 2111a;BP(vBBPF؁ag220 `PƠP(PF@e31 `X e `P( Fxx PFeg20,`*, BP @e<O\3 `>dȐ6C~ Bئc=2e 181 ` XRCgkժu B؉ իWoԳg6mO>Y D Cp 8@ jҤIO BE ,xYf1@ e ` X} SP( B`0x81 x ``0BP(Ibbb2` X0'0a;XBP(*a;v0 `BP(e0IJ+BPHFŋ/9^zr ` P(Iyꩧxȑ#6m={ `ΰˮ ` Bq f̘1<3?#G䭷bԨQS0 ?c, $Ed B8,_K.FrJqWƘ`-"@IJ3BP(dggӵkWfΜI~HOO7`؁EP(]9?q/3~x~k.{gP( ŁfȑL:ѣGSzuF͠A(qgP( Bرc>}:cƌzꔨ]6FbܸqV `88@@AP(ENzz:?|rԩS_b! Db( BMFؓl~KBP(¢P( E\X B BP(qaQ( "., BPąEP(( BBP(¢P( E\X B BP(qaQ( "., BPąEP(( BBP(¢P( E\X B BP(qaQ( "., BPąEP(pQ( "B AGJcP(E5AD<D.1cb1¿\ DX,FA(kyw]Š&h1e@fPBO. /XYcآD;(vH |S2y}{$8c (#"Xa-Jچpx5HvC?w/v(LC c (#"xG,<j%9+"ENZc X _D<J\\ <01[ EPʆ0v$tHIGRN6DtDP(. ^~|锚|"wK (DM:65 a*%BQM)GCR.=XV01[ EcQ(|MD@D@D@D@D@D@D@D ;SF)0;̄އA'[" Bs. W7 R`v>{և)&L: :f]n b`Q(*C}ևfCτY~2<BG(&" " " " " " " }ǽaq?e%"(>PPq+O٫S*A(&DP(BP(E5'BpQ(|MPTP, BPąBk"(Ob?PA(&DP(RAQ." Y 1`C(ry3RMc0`ABKJR>[kgSZE0ƠPE%c ZΫ[L ?B7aY!Lp^v1Z1(P1c $qsto7f<25¸ k-1cP(Ec Zq<.gyuM  mRYJ2 8/88c pp B<bD""Hh4J,8E1{z>[3ox/3WP(\ _4|oOiNjQ. _MH@F4ao YÌw썐7_}4wO3{\vpA쎐H3#[Nڅle?cߠm3 ̎M!3; [DpWka$c'p:+=vhs#oJ;(>PJrr\ozw[F(/:y> -s_qпU*:!9l^~EЉuq)yމFx劮v6mkh)z0Sy꫇O,: I7rspXQ>Yܱ ‡\ _q{^qApZq[SnqˮQWw&Ȧ싕=U e%dZقiRa@}7"'suCiE.nhghloN~OOz0hbO=Ŵg"˲ZMi/Lfm9¬p` Y rZx(+-"g'rĥD3قw{p5Sƾ]޽;ݻw{46cͧJtޝ];P/ )y0Ni`)v8$ڞ}9ş1sNꏘQ>A|Wtpy+jr1t9a30 1 I$b+6&ʦKXإLÈWŋYTj$IjIgPnn^:F^Kc3$?6Gk3b|@O?v P\Tt6# A!7p奓 טT$/y| E['yLλjϽ͇'aؙ,!G3[nS)akͳGOXQ&ЖLbo~?s?g,IĸԟNItX;|X\<ٙ{:g u `}I+x;S*$סB3. otm| ; ]I0yam{nzf7bAե)_oX؟aV,m0I_1_ C}kzw?։"3wfgrqx_:e'G3gY^I U6}q׼뮣ATkFl1l\8B?. ov+t?n|f_)ԣq7$b\R5n=N,{Jl#ಣ(ks P&MQvf6(2s3K _dɅl}Xi7:=Gwv&%Y(?^Eؽi0Y=p;[2I\~B. ϸ-",\C3O)p"kEtF$*-$J$ v +?pƳ3Ҕ?G3gY^I ؑ z B ;'s@(Z745-㶛NqeL u9(PSt9[M3 ?3Ovj?!-d7AʸmndƏ7G`1,u{L= OJųI6osGLby֩<4Nu٦Cϧ9=inm3yoٺ*o\ X<0^|sT>/Z'3j8.Ӱ o=kF8C_bl|1V=s:vyZpaفS7p妿O.4vG->;H`_Sx<ۖZ (>PO<9{^!.? ɛ׭8|0:ۏЇe' ]WLxK.ل?ϥim$1z&O-,x1_ȤyT m.6~[iհ Nm:eEY\ъU\vQ8{.FuS ̭JUǛύ䟏N$5 E)H4>Cس,j8_v X:s-fU O([ʴ7qh9z84NkU$r137_ew+qSơa'q)PTR. ŁK!4Inxr~1>.GF1d=ȶT$C{T5/>:.֦zSjppP(*#ruL{VJ-ʆu,~.{q7BNCx+xrͧrp|7Q-Ж2׽Ž,!eb  ۇ+'u >Ao~+yWхZ[j&-+ FU EcQ(*!Xlq9QQa봥Mq<[=ƃ/^+}z!RAC>qˎfɬEA+^d%EteE$F-/NZx2&01ZjΩWԣ]}P ͍'8d[:SiS[JEtPSȶP Ưc1u8CM1 : 3[1Ril%9`)F94e+A<Y8(W5t>  Ecru@ Ā 0 D CDPG`JF=ba1(ߚ1&Xb@ PTBÎ c0(( BBP(¢P( E\X B BP(qaQ( "., BPąEP(( B. Eiu&x0fbam1$3 z70\`Wb_GajZ89 jmP(ɢPֺbqb*%BED(Z"XSD|7(c -)&R^ A'·&,6)-(CpaTRͣ=,2٫yp4yE+bG{XZeWsi%Ż-^Ws_!-a"C %lBIwZ~.w%DzuacwU蜅BC·>[%(7p*iH Pn2E3٫V֙THd iK%֮jyF-Y(PcӼ:F V Kes_b'4bGNUtR"]BB[ln18Ɇ?Rd~ɔ[6EQvdTDŸ, oeABXWf2 ;kLakU1`3;2P!BS. oO3̧̽SVsI5wZ~wZ~oc?gک(E𭣳k(K9RX B}<ƯX`[PTn. o@L}kٿ%2(yEY泯6۷ 3 (u=g_m^oi"^ L@, o%80fH3kKlr[PwVP˾YF [%֫Cy,fV/ߒCPTr0L#gۑ k&s6HJӃLs.hi(qQ+Y IT?F0˾ײ%.je8!3 gܨuZc_`ͥ:R;ղULJA:)Ne6Kz-P `p 9(:cwZ1&Xb@ bQ( "., BPąEPZgRM  Ŏ\ BBP(¢P( E\X B BP(qaQ( "., bhaE=Q(;Bn;i9|Ȧb_nDP\ $:tjHVCE8(  (qwR"6PBx㑕grR>\Osqrvo(!J39DM9oT xd%ԦSR.a}8箤֐vRhzJj ҩ6 ǥS#l bE+9|jꜵ7o`bA"bȅch!©EvO ^A7쑷9¿[KWR56%DC hqm8{= piWܶV`OX9a攵3'镓#\6.(b3#\?4 %нs*O^71&]$qb+Ls9$o`qIEYX8(8[3Hߺ1͉pvU-\}heC|b}rܚA֍1mNCjC, ҷnis,bU W`冘&@V/縴n\%8ĥtZ.Ikr"a(y!.8rI:-^c veRj&c.$ "v:7DlҀ(߭S!@NGgĘ<=wc̜^ܪ tBG. Ϻi0bN(z&РE'y}_'QҧÈ9Est@1r(a~DFKv#1Ήҩg ZyއuU]Tj DcdAƎTvaf1AƎTv sF X,NfMP5)U2RNaح'QAn1(qdQ("}"5-z8 saj$¡TNDj~[ jmq2澗ICd&;+}/H dS7ĀR8/3oLk^LR&;mf( Fa\63qaLzyDjf9\hkVam %B\=l '%T9 74r#ug0"UO^( NO{2_ (dQ("Ic%#:D"($1iX^m"KvIh4zHCgE‚Er"R… :M e 5k5ϝsb 5k5ϝsb2)/=>n⓬TܐBSE‚rM ֻ;MG%A2 GSWXaCWϫJZ>X Epp BGCjv?Kx=Z*SF;(1cL ĀEPT~"0cQZ4VEx0&ҳ E(ʯfj/yBRKǎL=A81  $"2BP(1&Xb@ bQ( "., BPąEP(( BBP(¢P( E\X\WY~w64 FNG(Ғ"*ΉHJ 4Ctv<~.@ $@ @  BG #A A@ tSQ1 7..Jqoll|" @@ xT7q=;v31:a♄.MC"\4+n+RxvaC @ rߴQCy"[}xߛ(bjF|SNݠCO)rF{ML<%/#zxiZ6W+sd,om_IlxgeLML4*~sE2޳=Cvr+)@'t ϻ6 3Y C#OM!W,H?m3o7b:{ߠ=<uD <#SM FwWNO_!}t g nOĂstZ AV63; ^d ^;XW<R1(3]8{=7N +%zQ|w4 A잜{[@@ '2xi,dRq`/r_ħNXyBE;l;"Czdp/u!^AG Ғzɇrܳ+"BZ O`cWDt+h┅P3 (Q [V!3}=ڃ"9tJJ~ O䩐ŭ2c(Yݓ?dY|AϏ*Fh+ x'\)u @(@/iZ pn (@i A@ t@ H:@ $@ @  BG #A A@ t@ H:@ $@ @  BG #A AppY @L7xxhng4Q6Q66[6HmEߣ&pabsŒ[(^drkxF8Ν)]}"'\ģmp bZ["f[(CB !$$BBB !BMFu(n-z]61[?-EbĪ h3k\Y+ %vVrQ6RTLN|QkΟgk F)5C k @Ҙm ɋV$] ^_Ϫ@]]3;/UQ'SJi&Vm̕246C耉iǹ֬JW9:?̆#ч} ;&E) i_| V(Dϕ(65&S,t1ik{']-fbfTyo [Zކt:rKK?cxgtKej 3V"'mx9ƵcB|ZʸT4S7Q ԚFcKW Y0qbƮ)T  [ɝ p`/I,'_ڒp"7@KVK7Sv:x|=f34QW!(V(WIQKM$p״Ϭ:9ә+a%Q3>ܨ:/ž}؅2rZ4 h,vw" ?W_l:pzngpbcZڦ1"[:QK<Fw`_ w.(_ePFQZЄ{gUFбu@궂h* n>}:}?,6!#t'#nNOkL/cͽ.7}ۑ~,kOaÀR|I7T&> 39<QҶWܺV:)U8֝y] =q=&?sFv0]UdZU+c .@G: W(N#yIt]˹š Pnv;9' Ѐa1MXޮ;WeyZV:̧ ^Fʪ}ha F-J/]/O86ܧBXuK`:L.iJGpšҹ3V ̜>kA,~hԞ^J3w$_ߜ0MA;9w;FV 7).&yF V0 ͦ'i@6?@^iB6Z"]<v3,%՝|)7NFRXPJa]\2Jn.@Qw=2mSQ)h&\>4߿;:Sq 4͂o+?(JM&Iq s,'щcdMߡUI}%=_'e?`/E +Y4!IڮG2e -gT۠\.^؈hŖPJz(5q8(94AsԄ4"[1?L8Lژ+ w؛|fR&8Oộ,=ykqK1ץ,?A\EV2of'(ُf< ;:Φp;88H[#yFddtpe*21.\'DX{d25\dRШM.|i)3vtLh/(V~PLdٓ"XNboX+ƙ+nޏiT9eOPyO_ OW綞W}D r|Vh/^I9eۆʾo/SskN 'ZD^ݩZ7m;bh3Dɏj1[M,K&j,Ćgi#I.Yȗ+krM|~,#z?M*61- 3nNLLCx uh:MOo='9买˜z!b2B)O*ˌ?I dY35u+{(KzZ\rYg8>Npx\)xJDEGh#|V>?hSj?!#6dOKS'Ol\)^ts#r*fx]>]r$ _C2 nQo)_!艜qLWq%) HnGpB1h|x :Qk^bvWQ0q;M6 0ݘy g=ޥ8neK/9wMϸq 3p<1n5Kα2u vSq\8%?@Y* dT2<+Yuwp?kMSz&Z/:Bkq:AWi} )A$uh8|%7O)3@xW̡5qGp?ʏ|I f+7OΌ(z9N\>p1@c,)wl%4e6-MN|2nno5z1gf r%~SS*my }ҫ2>/oOVRic![ fc}kbO"4 n y3fe*xjO˺9'1+oX7nӪ5(|\o )+L9͕ ;2|IDAT  ^hcm=):$s7o\^r 7h$Gkc3&sxLF<==4y*ktJeIǾ?Dœ=-!e<㑯s:=(94APũ Uir?`޼Tt[fQ?)LԝŁIF}K_Qr2Z|W3/3iXpCd:W֡|˂-ړD UW#x9'GUxǃ;$kMY.9 3.7"cO] ȃXL֒w2wonIIN"#]xzϩ_p//1hKIyxl%?.I%Kkki12Q4%c/|+wup\>éU16c\G@aƛ`_5m8%&nNDV,z*e6"~$IG9=Qn&x%wPQgeP"tGdz~|ӎMḼ1=F/SzO0P<}S)U8ð:g4JKÚ<B-^zꮕA|z( s _aGЈ~# >.IBv 0ÉF:VGMh|*7b3vߴ#Z aw[ӁÿYڲtco]IFû@fUǬZ2L@=NStPxzϑ/d<({%wgZr%Nݔ<~c25G͑ .QaR]o `T{Bkd}g7@b}]vpRdw9)r_l \K,Q/06ޚ9&hjW8t)[.&ȓG5^n}{Ǚl۷q[s<3S rjBX%i4tפ_"YztdAX- 嚇Fz3;<d[I ' *L_@|IЈ贶k$hXv#=F`e\tDo0͗$ky|7 W2|6}0օ*VtAh78qcNgzl-b~4/Ѥ'5Kѭ~B93L֒w2`r)""fckT"'"+;rYnD!?WRٶ0yKw H)1d23歊+;rYnD!?Wq\d-YG\nŶKH8 8'ʏh,7cfvƟqBp _RUĎ6On|I$\t1LǍڱ?~ 27%Ed.K4:(QIH›BM"!lﵧe/>ǥЏ.n@̹4{F̩x/XKNK$#:[rmq%\46եM<йS':\ι#ͪd=^54`;LFÎ-e3?ˎEHY75AeƮq 'NĉYږ,oXx29Yu#KNwRnKk&/r~';OqCː-0@Z2m# M&eFuw4՗2y}:Z*~ӑNp"rNEP%I+){Pu>z[g픤)T ,)43o=̺ aE{cߏ":@=`ڔk&/I)V.m:}1]6Ν:yrgiV$5Ɵ%{9ud"6bvl)Yv (Bʺa_? ̻ؿc9g$R`g "-B݌bYUt>:h)KS=N܏]<R88.%'U iM ,W1ogՑ ?g[F{H=dkzn;55ܳhb2*^ŷtWEt(k&%3o= '|Ǿ3hكpϢy|31vظ\~y=͇;;sG㔮XetX c}x=ZuO0xch? 5^[]?zbt4:T+fLbr ?Bb䈺 #cu ·vφ+r܎y&oJZ leSůX ym wx/WҽCXCc() tV R(Ph뱱$oޠySu7~1^Sv4r*=z03t"jc2>؃gg& hN~okshPϏ罣_aϹWg*3f\0-4◯/!5EĎwg\PY ۥ=Z0ϐ(V!$ՇNr6K̀c/KCsq)I#3M^gWۑ/τMIﶂvlpw`"0͡AoC=?rJ^V(؎V34E6Oq/`M4Td>lм[}03&7'DIQ;Rd88i\X9ER[u3?]@GY5{?@,~nycBEեtp?'4 3~@e bi:'dZv;D6n\qzKa@ENyMy O罼sќv<ŏdm> $U`/o,MN^R6fÎUL=aL&#{Ig K`3H?`P l6ӂɳ" 'P.VbȊ|6sI[nWRəT@ÿR7&XSW\'ϓiZޞ'Tr "G Ό&OYHU=ap|ŭս ˨u18}&|֛q+@C M`,<O Ry[ND? iҤ׭le hVb'܀p@ 7܀ (@ P4@t@,0D@ /@4\ pnL@y PL hDNX @ P`n 7܀0(@)$07q4@RQ (L 7LL@88 0 Ј!7"007`n(2X P2hhh_F P`&`&` P")@qLb)t@4bi@ e` P""i҈4@/(@ POiF,X4@#F,8@ PQRR""""ӈG#4@/x"""{@ @ -W-)RLIENDB`deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/png/help.png000066400000000000000000000621551325241207700246560ustar00rootroot00000000000000PNG  IHDRjk6tEXtSoftwareAdobe ImageReadyqe<(iTXtXML:com.adobe.xmp <`IDATx|'IP(=Dd,QSD@ 'TpQQP8@@ QleQ&\Z#)~޾rsa2LDo.)Hp`}`}!trY6\,#@pru5/,|keޅ~UXj"0 +ۿ@ Vv"d=(>}_p`d28 0g6uoٗoeNf[.o}AAZ s2ٛ& ,ZS-ۏ} /n]|2sA 'ZnGF/W mJ>ujreTlt XL&sK)~r29c亹}RXZ8!ЊRΑ,K,99 㪶AP08 r,Y* q`57*/J+b%q1|y]Nq Eԩ]3Omݶ㲟b1[+hJKK;yyy*>>>sUw!؁CJLLrFP`Рbzh`3dnr,W5 Z#!7F ƭQL 2B.Tp3Ӳ118x(_2C%i3?/ T;B4j5[M%}r#L}2yp%*pPlypnc+\!FSRSr1ss\)@r;pE %Rh!ɽyGMFTʊJ6JJM(Ep9}hտ_ɷ`gPf( ժT+ iFJr%Kh}r5Y)T-n 2%/穾ZjyBWLu:-#hᑼJ36Zg]GfkCwUNЦY3>ʚk.gM Z&=V:~-)uU'/&*ժK?M0+M[LWqx-nR:Wٝȯ dg{0p@%''kĉڷo`s=jڴFFUU2R?,V۵|;W{՞6V/Sd}.fVT%Rw׿Z%5jTWu[u15S'&WKzVh%j::i T=UjXMp*5J,o-M)YjF.9˭{enOP gdUXU;Au;cغD<,jQy5EҺ<JJ6S(mQy).Ґښ҈:0]Ʈ M>s`svV&*ܧ? !ǜ-XutSC-BWO%5nX^ަ.HV>, j^:+^<^-ʖvZ? c+)Ȯin9O8g糧kK/6ꢾ4q 9f˻|}o}WULiO%WRiAmt1:HxꩧYfe=ݶ1usy`roFz{-6{U϶d7?Шb75e|JWRͲ) )\XމOR{_"J5uW_i҆lv 3ո@b.d~aL~pU޲Gf_O?8\l}XSf[Qm\FVu`OR{k;|nlAŲR6_pK۶m͞=2ƼZj9]pgWѾޟ>N^a3hWtDa6U>T8/Js5ۮ_?En׀_5%~"9ѦBuޞzd}?N/yM/MtLw^We澥w5a;|TǢ: C?vSجJIJ?gp/RLfcj+NU*c&SoN$ɳf 5>Ci 8ÆX'U4Ѿ?HwraRwjGj+g~M:|#zP_Jz^-7~;SVixEXj=tom_/>t<1y^x!8P!Ҭ#4ݫ$Z/\讲wWЩ_j`==*:VߪDfԿvO{_߮S.ܴᗏ5akBD=-n\(?_>gÎ\@ֲCttR~pitd$Ê_ :vmJgշtd)>^ڽwz`'~,ab^5IԆ_[+<h:Ɩ=ZE)JcX u<}7'ܾ}հ[/5]l4XTWT@B˖-5}t2;w:wE]b:}rKRR ,QR&Y$P%K&'OU´ =Q雿gt{3NRuB$\{8A#¢'?~w'(iE;Am:/{ {M۶ɽf_}RqUq2c 5=Of=GvUU;-2.u֐w;gZ^o_z덪ҰJ?=4UnUUcTFf7ٰS}۾V[<)A)fw9tSqJwy 8NZC /.e}ye=R|z =)(B;WؼyZm/57Ku"ՏigկM y. LE#m}H-5/:y]V svz'=$mOfR[[Cv EjȈ2w$+۷tKMku =Ds[{kz|hSQoUu}ʜ!߯SenŨq`KSE> CpZѴI `.-sռl6ɓ@]-!8XAAAڿE39i+SMgqO)^jV8߰xe\Ը7:9I*$OO 8YYe( Uq/UhPk"xNx~Njk:crm6$X -_4cs*5#Xϼ:G!KzJ*ڪn Ӗ ?Y(xRߧzD2z_~ g,C^רk<YK˹y<5Dܧj[WWkf*%5NsSdzwz\KEK)*+|D%Gb=%H4>_*⊹[j-wGNj٣ |+7Q6*%^ma5T!E@_^س*tzN[i4SY.ՀL^=ÖәIFEV9:Omij蟥v`iҰ~|XO]wA:QFe ɧRG0.biU>-[WIfiC-몶j{kjӄ9rlOUZSRfy4z\]4ybL sWmV}ýԺMrv[O=zQSJsyt@Vi4=^)C'*~~k͞zGyQ?5e TyjǏk>pLW|>ggsuyWjl=ZH?[-s-O}I8`;3"9oٷN/&>?P?H zO5Oɫy~?WA%d-*~⭊'VqrS~h-4cͱq2wZ֎Sow?oqG6ok񊷳ܗЙ?2#nKwV<F^\YR;;Igr꺫#,I;-Sp:=ӹ.WB9r$ebND\!&we6E& oZ'kӮ3 hP~ʘ_ݥ0-ZO%4Ȗ{J*zp>ǞK4\&Th@o|B}&KWWT9PZM z; F3ڭ='k-5۲ħȭA?}Dcy(w6}U]q;:/ oJTy{UV RӊhLEU:G*iڷiKT|su+3@  Zbժp/N}7W^w{z E-xOCfJ|mgfkz-)i :L?ŘedEk]j.ٛ[ozo.z:f sG'T3ӧ#eH=l \H5tM/=4P2@:cV*W/PAǜݛeVavZ|-Q#M5oo ,&\ϧLxMbs|JփfJC>-q^NOR#5}1+,wcsIxa5Rq.)k>բxGW>U3>sczf\^Hu|Uuh "UGwcT^fccċ^6e֝"oQjU,) cM'V}bUݫz6x~{;w򴟲;V~>~smY!m4oرB]Ӷ`P9v4m[ykU=񄞩hш+~"d9]oOC|>UDk݄5gϹ$mJ<ʶzf~0OVV2EsĨ}OQ\M_wL'/ޭnwk/ڧ1Z|zrQuzj~^uW T̷gXYenʯ?}Z;([M|Лz]T JG{>` bŅB%=jw6Z.Kwә-3n8.|WP[LzIZ[vSPvvzB hܓ]jq_!YOxd-GkwxSQǶ!H &zQ篩G>R{ԗ3s| u&pIfUl2Kv-XmBF ˗[nC=ɓ'+-[Fh`3j%ܹ35ZV[nxv4ToŒR7wU;kt@! * W95lQJfdmsrRjٽB8Ο^/uփMvQN:;}l6 nI#)h#y<,Wqa.VOuҒUzM7*>Kw^:E%Eر쯛5Sp&-n߾͵f$m|NY缩"Ptz2]<|Lkc^w~sR#=^u (8(pM-6)]3P[1):3n^?XL[mθ*nOY!ENHO;ЗټSg|*5P ?Ÿ%z9Z:W꯬G }> x6YԴ,k:}/MEgV\ώײgh>XS NEFZ8=ÿkٴz%6:Gϛ;&7/OYbC-~P2*EFrw=KI:u,/F}kij;r)pjԔЙ,g5ƌ}7мyo>+VTvTlYG?և~ e6vr遷>UsC6{ʼJf_S ?ܲX_/> k0XԵ\XcuqԠO/5m{ǹMЂsFEoUo;'+vS5/k}~RVjQ-w ~tGY-ffDPO5sT-s"l?sp\E1rJN~Zu}OwP/r9CtI qp`$r;zϕ[וܮs0(ӠjyoҒՊU{ա\v^b`wdKVJRW5yrZwяo;?-ѻʦShrז:[hR' ۨ u0L7щĜhs醺~ T1S7Ǧ¥U6#:p#OIN*lL[|&s`g*{E_si.;W/vHo{[s WsG-_'66VFRӦMժU+=JIIqi` ۷oK/r]4

M-Joh$RtpOPYzrMB?OPQo -r=uTtNiGla.[L`.uunDlfUVa{ϙu&yT6u*rr&6M%_>՗JG Ur|=F%WU1K/c*y &wO^ISRrjy }4F_WX{_k}t7O?ꢖ];(ۏŌy&4n%(E'_/suo;߯0گիhžx;!ܗz2JU-M\}ML;iTgM)Kjdg5h +"&O8mäB>>O[bc իW;&g>cˎ`4kpz&h섕::SPKܢ,}]%*\iCzJ- Gh{B4~\Fk4ÙxIuc?U/&Z*}scozLv V :\DE̲şRtjX,y6߫kuRAkxsDKQռ?IJ)|0"E(Zub=oxEu{+5sҟWh\ViJ޼]k#齝2mCes7UU jZs NZu0;M{BF_gzO5bњͅ @lBŇi޸6ګ[OQ홚X+lSΆ4hQ?lgt:wY}'5w\[Ǧw\_ Y4ɶM_6$MGad,K /| qבK'34|HU(r14c}r4; ߭ɘ\_Zy9۷TewjF~r<#&Śb2QԲg h#lسLS퓓7+c)bp l"8(5TS7R(FStu׬-:b:^D&_3v𣏕oG^Ñ]5f&U[Gm/L|mڽۚn KON<㪷t;ߧ/3-fҟf9PSʾ+l7SsyMp7j7d4J4W5w2#E+]S.-2mU9vVllV!-l|whΘ4}n.M#;+'?j('5, *$sZ"p4k֬?K8ڬI:\ Lz@ (WsLE{`~iےܼ˼vFꤷ{Ҋoƨsw֞G*$^K) 2˺,NMc^R?(46c,jGzsi&!40E$=}wL&?UJz8zg RMT$S խZ1T&M^xڽ!\'#7i9ڭz-:1gowj+7g=9B6_^\I[׬;", ǹ ?oz]gr<*YJ6"ϴ_4şMf7UR^ڵɾ1*tRP0]n 8 8DBnjF4Wo[ﭪ'gwg+񶓋ɻ5Uz>{=B*eӱ}w h=:G Q'#5ogXK5Q~zkk?mSʷŚ鹯e57PҾ1yoV]:l>naO\r_͋;ߌ-/{ONn] n__[Ϗummb犊۷JV_({VnSSŏtupO@Z]4ު^=XG'u4¤6Q=qJȅ {hLXE\6%nbQNz8𭯆U,JXM{p('nnLoczk+uSk mҮ&۽L҄Uq-UZyڪ !5@z>>BShw^*XlLCY3=d^xi _z Y/לu@s 0F)Xj'o꣙.3}pvwk^|돗qY_•箆=.dn⯽=YM{ȸPm!A;(+0k6*4t6ZO=^:hMR27dEUЭ򭺵t|jJ|nj ]Qgp(ŋ440~k,U KK>.-!}wy}}Tkt^ߵ'լORZ?(Yfjdmu垸Qk6'fPM (-M6+MqR_ɆuBXLrZ?ٗO:X_jEUuWn+u ke{jM*x_ڦd4US\9=j߳*V^v~JO` Ն u9R/cPm޺70ªm>z,'6(KIQ[M5oT\JبQ\ SzXaoOcPԼ=&y*&ߚN,L ݵ$m3޷ k%LǕ(Ǐ9YL=P5 D7 8tFFDfde/U%{㒷XE\ˢiգElE LҾ9hT!jfrOůYu{9d&*j&^2FSV*^6~{~wǸq'ud}Z~\[h:tFg6kUeW7ɯ9Ja 4oSJ*_Ѱ#2z9k-ҙumď?Լc;z_:}7[T%Şݻ}n=R~rXJfC Vl2K'^(m):mr1.LN|_stFCr`lN+qÏ3Uʏ+a V:$;n9j(ev 2Pdʔ)K_@d\3~RRR V`/vE毊F쒆ב^*>uy*7vym+zN+ХRҜe/k[6Ņնsiħުy`NY4ږvPHIZX~6O=_:X+WRJT";h!?%V4_S|6Eq˶~Rn Z䉑:q i'B5JB Mޚ c7kޜ3ZSpV=[ա=EOsj>'}};dۭ-roAM{!beU5dŞ<АuW~?Q`(hɔ%1ySw_͍8\QRHzj :i\]95Ke_'{WX1x1dLi&[ҏnQҦfRӗoW`ĝp d0n%1ySwoٽ+&)cJɘ2M63 Bp\"8.K%pDp\"8.K%pDp\"8.KnyY(O9sy^>11iEeg1Œ3"dy窹|\eѢE q1kժUA6o|8;@pw& ֭EDD8j'\ F  ZjiӦMNC6,^ ) FaƸ}5+U#00P ubŊѤOfszF ;vwھ}{e]N7``Tp͛ E1@W|}}yCP` O͍ ЀZ8kKUCBB^tZjNra\|g3;{lѢEy#Q`uA+@pbϞ=;wmbQ@@yHWQKH1҃3uq{Z`cBP1a(Eq"\ htlk׮\xb }$QV-f͚G1a qؚ5ks#*@Ub}*Ug h/...<1cƨFP}:rrM6 8\kv]b߯':o}vǔWwq#<CS\tzgUqWd]M4QÆ ٩63\cۀV۶m/&I~.v&8v| *ڴi uz0'< Ӽys.]Z .t)+ wؙp d0n%1yjͮ\Ý;w:qV@@ʕ+fsMRƔ1elk1%%EJ? ?4U\SFXA9"pDp\"8.K%pDp\"8.K%pDp\"8.p YbI1+4ݴ@ B(!Jfwĺu&]%E̙3٦hŧZO[#;ABY.{y2d~(k{WwY"7-]1ԯBҾ9sd> &3rFكZhq)2omRu:6^HToiFxj*7Id3KUu|{YӴ~GP*$KOlԜjA5+NG Nс#J6J&XmH_`=PKCtNu5c_E6-kRTU҅/iR/ӌEa:bNTXZE9 ]֦MWWi.7P'ڨ8kOjuZ|p4.%G3:qR^mڲŬBUrA}Dg}&O+WNE3dNRڲ,>-UW֪!0$Vu*6S#! 8uP=:P_f/$j߳D;]sJQԟS5Q=Ԩ,NWJwtUhTyH[(3&vӫ%l NUxRZ\~6oR]ԑEUґU:iJS=io3UgG/vdP hJsכd)li{oK+-xQF%i5MU/=ظӓ6[͟@UX=uVg_x4MXosc"}wm~Y?ձ]Զ/^a7tT[)II VYgI%nn:ϕ&?O%O~$9Wg"-Ԑ5&.[K=d h~o4;GMg+qgz5W}tWyʨh0~ؓ~zg~ |<2|pkj3]پmoM9zm؏2sv,Iˮuyֻ͏֔?SzZWGs/VğU"L ٹr~iO?|K3e̩G[k^Y8S./ͶgcӻyPI\ WnIݱO͇:.snȠ[o}7s^8~n>>L6rihXS+ȘE?1gݐϝ6<˺Cr҄]_@kIOqhWMӺrMi9y}\N̔p~=[?&4g#eK٘۶4|OdnbFuc& rYuϭyϙI]0Gg?5j'^s+w윛|lIWggz[c5gȐdwS% ~jtwrdO/M]Fy]>?oAS WNh˦O֝/܌jۛ]*oTjzOfSv~t>s.R[[I֥-|eȩIc[UeY:8\.;)_̹Њsru9}+8\41/<14Դl҇1d {Ҵ&G Q!svd鏿z]? xH{mU_w}m~֤aL8qJf CeHegfdl3nWR7"\ 5O_Q8mk^ښOf33}WMAԧ_obۮ-y}7)͠Nfn]=?U]ϨfOx0,^GVLmmTfe ~,ɀĩ[rעլ4uqi&2޲<۪]#s݋\se]~ի z2!7?oLôsr͹eІyᖜ}֔nlZ8idv^X4˞z1|v>uG_{]%)$cRN%O>?2"| iz9k7Nmcߚ 1KA9ʽMtΩHMsoN:Ё;Otsn{eZeңp{ooq-oS3ܽ HulꘫPݕgX m 5Y]ͯf7O.+2Ɯ?u\Z6eٝOtyqy}sy\q‹Ž?݃OLdZvfoV:7_3pQui鿦}߯Ӝ&fECu C&fsPͮ5k}ډ۟ϩ?dޝ^<_No Iŧr̝{Ff?>UShg'aXM6<(kKN~ܷcLθꊜ5.}۲̚ԏ8)M3 o؀Yw筹C_0uf[xcؘ ^\#W;,tuN횪+Oqs\]뢴eӃ?ͽaAvż>p::WeUS2hƥaimIfֶPn_Yߧ6F֦w|N~35w=r99lG8XD\Wr.ds8ڏ۳gċӺ,̞?GH׸bFoM};z~bM~ +:vԏ͜k92ɰ3osg3`[zz:t]f9yneZ.Y]ג ΐ]T_k_:3Lfv}?5MM/pkfn#VxٔgKn~c2mʈn/XϜǟސs޽Gë^yaoS炨-=+KPmMKK\JW8hi4f3SH9Qi|<6 `~cOͩ噛uocW զrm˳k܅ >)[^477rf/̄əgZϠߔ>9<5 >$nT˯;ؘiW-yn]#}ʛlcɜ7̃jk;7%lX p{oԎ &HmYa[CN$׷極kӱ;[Ҵc֭_靡&fx޺K~m{LUecy19~ά+#'|(;_`>ZegԺ4ꞗgwr'NК32'G̋p7|kZ}|/?YW֬?g{\OvO>+wԢCzks۲e[5uc{<rҗsWCd~渌[7>ސ?x[g:t-w=GQ}lmO箟/ɖm//n\zaoGVCf;}kN|!uycæL;='6,]UٿyiY7`y^;:;/g8_J5-"iy ?|턆  85L8smV;}>5".037^ԏf CMU෽{5[g{e9R^&˯f@i.j97羵cy_fmsZzI}smF| =|ms[Us= 0%,% G%N,38W,:8bֽҚ{Oc_ëʝvf/ΐfeմoS: ٹ~CUӺ__N^5E S3axS^瞬T̀}_ ؞]n$Sn3cƘ+xl9~G9vZ߅]yaCǶ1Nd?JxZkܽ`QW\+~gmn_ߞ?~fNfhۺ2&eޕep5ox(,|2_ݑ}Miqc֬-X4eQ0`Y9p6eS̓sXSC}vgӪdz|Y)uNe_(3G6eiju1|rQS2c֬:،pQo.:2Uo5CfLҹS,1)} ՘![{Oפe9/3Ǧn,[hVwcVBψ|+ㆸ9Gljln?ysӯצ2,/>6&Mw,n>(?\}},,_oPm˾isV>{Gs^29g̜'d~]fg_?y>Xw<Ň o2hmk8ԚCl^ oIdymǤL8mv&wmSM!Dcf窯 loEJ4@F]MuXC';~ 1U>rԌ+Bum(mmm/>-&}{njdXVjܵv۪8#P'}_O@p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @p @ѻj}ug8pvq{[)|c>׼+Ԗw9y*yK8z]6ngt]v=.GXC394ov[c1/JrJi[`AaM:uT}}v7.4566.7kҾvpp(tm][nۡ>=AsW48Gq.qVw`l[IENDB`deepin-calculator-1.0.2/dman/deepin-calculator/zh_CN/png/main.png000066400000000000000000000441261325241207700246500ustar00rootroot00000000000000PNG  IHDRT9GltEXtSoftwareAdobe ImageReadyqe<(iTXtXML:com.adobe.xmp }DIDATx|%MwN e!N WQDŅ"P^e@t7.M!-I.hlȼ{r%A$IP1I =#[|lT3p!H]Dtd6ufJ+X V*a*kKB %1X% S0´लp`JDdaZ0PE ͅ 4@U$+˓:"Y"BufT- 3 OO6jڍmMD3^|`ٳf̘qLB4L Ӧuo9iҤU*#wJֹԩc}vJRg1@5IVǧ*m伌WWcָjPst٤DTQyyyvʭj-i_1S"hRA)/Lmy1(!:K}bάrxl5yyT:=>Fg_w~ hkc=4jeDT\V=E s7NUoADJ*y-#"{ |, (oKG@{."riVs zZ8%"; B+TK*T L%KJzS))t 5 xjec]io:5PGTWj]˙(EDe+,,m7o1`;nERKT*Ss]~"94ӧFelJر~mCajjD TODT\*U U^t˖-^5Pm A[Ж JD%sBu߾}K+LK\ڔOЃ{[iB5kc9,`uէLRjNl2=iU1>jkKD%sPXҽ… 1qDQV2Mt֭ GyFBncR:IrP 0T~gܹp`*o:޽{WorT _^|GJxT QET!d1PDD T""b1PDD T""b1PDD@%"b1PDD@%"bD$k_XO/Y M"b79;f^,-_]w=DX zLG1i"xAhۍsq@u߱h|ѨP _KpԸL9 oƓczgۥذ3ͭ˱h9I%nE u]ʨݾ=^*AM8I4t*ZXkSVDN @8ߑHtC>~hkRhc84|n&IUxвsUZ0J5^/a_/@CaP~řmG$a֦4τ? '"~=GÄWa~TmOGiޱB% Bwjz|*#?H8 зLum*j>c_4]ESc&S&ΞD&O]Kc +)ez)^MV Vӑ ' 6m Go0kg!>Tj{@%*gkf:2I?v^:b^hP97$I4auu:Qow*?l)AAI h\Ndz+,W?L>2Z<]0L M~&ZB b B= E`<_ A SYwJpY-}Q!HgRg4|=@R j0-J} T"\@55E X2?Z_k/AsU]_`vkUםk$GKKر tAʑI:j9$\推Sw!23Ď#f_$ 6 xR:XZ*G@5o] dsQPA.K6 TM㋦0UBnͰۣl6j5N/1jޙ"M٘EX$q AZ 7g!_v2| ϼQu`6VA!W.n3V nQ~"iHOφ(ȽGN-OK H|[hX#g\1lz#&,ۙirލë#b>\eWU&#>A{mѩl^sqpjDsߢG~šԖ1A%#F*JMT-Ŵ6Vڴ̇Q ɤ1NN$yiڣ¨BiN|97DL3cgD`8x6 ٪m *wkWLb3<]~kS/46Xg}os|JISKsQܛn/"WNBS<9l\"FE3x:^<_}3%u(<ǩSW^jVoXnkmڰFi&eR˓8M&JTQF*byPܥ:_>XoGUU%6H*ՓD8ۂ֯bD +T DR j:쏇KȊ?X@BQ~ D:w8WЊ *FD@%"b1PJD@%"b1PJD@%"bJD@%"bJD@%"bJD@%"|3DwUǢ"VEC1K\6 `C8@ 5 ƫ:ݲ˱h9I%nBi-ԙ/޺ŋ9 [ʲI3˨,'hc8<8jw:?Ov^ AS;Α֟HࠁF (%aޡ'7*:Iyli-3醖Ͻ~չa&pY '/% Z n;DZ5*2[[—ODJMp+(#$jIc$IjG)B8M+Va8h=juaUwɿ!BgZv#а}I)--Ǯd8À}̻:~Fڈg큚`pߖUߍws[fYYfk`u4fx,d ?xGx ުb=7^ A)]PYwm,7Oxm~[AVy:񛙊.>Tj[f2}жi0<`H@UYyJ)g)If:2I?v^:blP*EBjT]gXw,z&9l(:;[v(ȶpa,Ir$֊e:Qo?VQyqUg4|=@d-ju0>.P5GZ;yxkH4R)?׆:P zMQ1VKm̄Z,;ě}k>.؀IOmjܪ8p Zi2n9sc|ckslۍJ]X}DAشi|).A8gM;䩄.ݚa˷Gm\md!ZʨW0T߼D|DCcSЏ0wi{2~Q?Jpol?_XZQ5q)Q&EYl۽Pĩc k*Q1+oSZUhԶoALL 5Cz?rWm]BQye,|i̛1'@[I4䐩N};!|?85Kpw硒jlzdd.Gj1n~֨l+!o5ڢS ؼ⒯ j*m)7!xxwŝkh_+}}68{k2mK)/r+#$jIc$IjGRroЙЕ:`̌6h$d{f>ܷ%@wcY"qrHcp; ͼs;vnooc׫d+]A˽b*`*Iu~n?r"9.pLp)e/*rJH^5}GN1jǀac=@%*O6b/d%rb,OGŭ씩e(zBNaٱpH6eOF@J+aߑ3|SJ7DKJކE%B T1O #]Z^;t qص .SfoSqx{Ȑ*hX]:D̹عd>'%>[~y)sZoC^ǟޖ/6RUxcx]DDq K] :otdt,^zv+r*?:SWj/8!AU=[U 'wxm>o˫’'Zf6Uuz~3J<=ήNAZZU64AJj\8Gk6y,V|aDsfbH*_|k+o|fʕ} }U^hh6$Fc۶ԠՕ<k_CȕRyiCf|\4$jzW'z+WE GRշXr4.NGfA{Y{1lCI?ov&PU7i T"_m 2NFo9Zh;Q;j%r,œuU>xxhvJT&E%G PYP8?3U+W!X6 /ye| wDnq8}6mu[CzV7<="}Gn=#^ٌMu4&а m# H4 bQat}E4BBᣔ!98~$*QXg<B,T+h8+3עc}XJ >_ƞڡ"zyo=7TYL#lC^#eV`5B@Cǻ TB yxrX FƐ^ Xp%\î/~?cjoUc:5񢈌=X^A~-/F6І^oFx"Pt^P (="wÙ*=0Er* ݇ÜJ9Y>ty;|i{Në?`QwMmx–K)ؿ(;PA{ TB.np1HT~]0)[lդ8x!4r&?Z8~fOw¥D x<7;v f WG`G/O5mXc8x,[SUhuQߛJTXa`U`u!U $1'_6#y0;< >1uMY/) lCtgp|/ 7k'3PU0XsQ1&W>(h#O?>[kKbm6HDHTHZ*^<3P EݚF*!3mgef3vh7gJ4C~7>RO:G}_ ߆hq!"27t#-&7 6l,#8vh h*{72 nu/rnuÕKWmʺ -WqbaX@{2*QjvfuLO{$" A%-wQJO@B $_GZ64O+ϦAGЧaLТ_p?I8z+!O): >_k`HH ߋ:%O]Pn2X7cpx2rކ.ӌ* TrNU_1z<9|!&U^71ML9Д#OƜD,\ΕMP\{_9ТZ7sϏ@'g`wTlZsp5'lE?8?MSt au|ݽurjckmT!17z%V|X~"łPc@;<7y+)]=1?U^O૵wy s:7tp->~ؽ ^t0_Ms2Z_Fִ áCk4fr\&)o1NzIbJTn'Z4/?nmhJK!;!W7{zB% ,+T""*DD T""*1PDD T""*8'3PX1PDD@%"b1P,իl)"Ԡ T ݝ 6dODD T""*JDD T""*DD T""*DD T""*DD T""*1Pʘ6.ԫW*k*Qc(sDDD JT1ݸq֭Ê+Yڵ+ =~ ,X}(Lɲ^Zvk>X]kZ8t ռ+ }=\C͵Y>o1DC={jA0c5.q / EDl7>2v~6RMJJG Ԧѣ8}trrrrJ6\퀞TU>.+T)0~|)5yKz-ZkbQ^؆-Wpǩc^m,66Ԭ+j[6ڟcA6V7nf͚ 7D`` $I p]m7zl^ݺxY0#z qsÏ$O9#J@1ظ0 y4l/[SEVG7wyUV}m` [CuR$rޣ(g^s=RBKq z0jETk֬c=f~-ZI / 'Oy}u1"!KuUDՃPF,sPeg$@l:@q+LCo>k8t% bKO}@,Y S S%Tnjc~J7~CN cgΜ1t*GΫ"nJ~C P yC3) pvvYDx8d"6nBǃsr &ж\GcDŽ_n읃.'#P5Éy؞ouF} W棃PSl*UwXh*uٲeÄ  6mfΜ oS―Cᆬ}-B.]>౓"4Šq31Vɟ߬ANN. !TuUehL"Ė*kUO>iRPʁ*`ônc5hVLy%}/, ՠ"av4J/K^dZޱJʡihZ0P5z F{A$ ޞk+*laWyi8BC= ӵ8$>qT*UUu _cج$vRK<'_bB\<ѭ9{A׾BxE-&cx?V;95.Kº)9jsW>%7or3:lLRL ߞ1}~ZJr+=i$I^t͸.݆\Kא싚M;W>hU͹\iZZ eǏR3j݃_ 94EC՝؆C-w롉x9q/L+ ^C+l&OJtIo2Iv iZS)_0dZJﴴ47^ O\G^ȇR%/DĄQש| Eor<*$ى%?n{$܅jiCJńh j0B慩g[pUfdؓZ7$֯ĉx[UcWo|<[]_xmS7THl$뙐zKEшWXTZcܛmۯy-hDJR*UJ+aj"{rέĂ=^82MmgfQɴ-7D.`4nmݩN'>S<Cu1TGj!L;Z,φ6dnjlgbla 8z| vztPá*DPu۩Pe Փ's+]sôJaEJ cq/tz!gJ:]\Ea7ps[T %UA !#si'"'- ,Qmir8y;L1@;L';Tq mj:-Ze 99~\\c᧨4*<-?aN[1o\Pm7^n&}"R NFQyZ8x:>' Wafᅥv4,]t-< T{[v#QtYvKOEFn;-Nn Sd_b~ Fl[?= @2+;-ĩhqfQ.= UŢZyfi^9Jvxrr*ô\00j%קIKν2<lE\]ǹV0e|i-./BW?ӢIK<*C`[o~'Ϥ"qCTb]ws.oW"[x'E#=5 b{o#"/@Ch0r PX\נ㫿źGq6^gPct<{BV/ʑ󪈛ŭ~ U[af̊X'>I#A:& ڠ]-ܠ=̉go/j8de CŅ!ͣ7z^}'#B37Mvz\qU%`tOGj)8mPۉ+i1w|`F?`rUא4n*V?ԿΩ+&ݒav?6O&-*X9^kl_WoaXXc:Cg~A<,PdN@C7lBT yR7 v5F^B[C)g.C>|9j_@0-f : BP E]c|:N.PsTYP;h`Xoȅq2:3#u[4BWE/vxfFWְ BxTJ}mix|>MFZ Ğމ3xGULa) <9-א`>AO-_ČinF̛:7EqIfaeeu5|{ W s&bu7hB%Q1.a+a(o''I(Ά` ;,S/qP>*;M&]~"R@%"b1PDD@%"b1PDD@%"b1PJD@%"b1PJD@%"b1PJDt3ʯ%Rɰ نlCz+1ېm6dDD T""*DD T""*1PDD T""*1PDD T""b1PDD T""b1PDDECı T"$3"H T" >g[qػm7N8?O> ЄgoX%T =aHךp<6'濰Ix B}1OK8yv=38LL>e_~]N147’)004lB 6~4R[bЀ0rט3 3ƶM]z\Lod Uۼi=k\`t`{,SSзФFT˫Ftg6/jTZ ]kQq)^d#ٰx6 S#oUx# 7S%6*2)+Yp+q1\qoFܴ 'NOc4ca7m $%"z)^z-ݸSr$*dq&[^ "O P T*+{ݚF{a3!dIh>M<ʛ]?s =fqNc!'=T4G,^^@?S{?Z99}Q:yL8` #InsjԴӕ; /U~H~Ah :໵gT8 Meh?u4-qCZb""`REm_awh2f}]"R#賓;PeD^3*L]JLd成 "K+b2ӑ8ő 3|OWݘw1#2RSMvpssr"=(Vڊc@툜B1}*`E'ɤ1NN$yM^]efJS1jeNKK{?0r< u@| JDVV;`/ȝƃTDd:_u"ܞ}CeQтsE[M"*QE[|XUbQQk^Ro:rXޢG[fA+ca~öx G2( 쿀Z^G+mBa?7Э'Uz/2^ngzp:0pjii #}08C('"7{*+q&uj[IjAaZ*}YJQwCPWZXs!Z"*."ՅS> h | UJI <+XU<\NWZ<=iC) x\ӳBjy Tm\:Acfa4ȷ~i9QGQVF&$W7ڰ~ dd+cY!y] '8BSZ:u3L*Tc ʏ)*1Ps*^" 9E,0br7˫ܝG N2ӑ~JȄ3\ۉ\KR8/=A>Q1:T,WDei7fC(<)yʣCͥVz\~Sr" <>8|Z$z*l5*ZފVf"/@YrtPfY^>Oq7_[:yR+y*}:ya*^ٻ6\^U\.وjtT<_Wjo^)M:O4.w+oy99m%?ZC'٦%\,/8E~jQc_% hao\OSl섂:u8]׀Gd`g fU-!xYvǜWu946Dփ6Qs_0}tzaP+ryC%*_j0nn`gaGT. PX4lH =3ODDeJDmX2P;/Be+T*ݛ4"5\6MR&*X{*5lW0N/ÓC-+T"&Qʶ&nաUQܚU+Բ?,P?CDzH_^Z*K]]-"*{8R^=**+R T(][jڍmIdۿ*$G%Q(:BU\|ǧ/季&U`TU+bKMگd1-V*+!P7+sܹ*5JdAk<_e2)dqCdeƹ,4I&S֔)SNI4^{˫JbWy[掛KR@*iوuioߧ7@61D* ygU89'ɝ7 deepin-calculator Created with Sketch. deepin-calculator-1.0.2/images/delete_dark_hover.svg000066400000000000000000000022451325241207700225470ustar00rootroot00000000000000 delete_dark_hover Created with Sketch. deepin-calculator-1.0.2/images/delete_dark_normal.svg000066400000000000000000000022471325241207700227160ustar00rootroot00000000000000 delete_dark_normal Created with Sketch. deepin-calculator-1.0.2/images/delete_dark_press.svg000066400000000000000000000022451325241207700225600ustar00rootroot00000000000000 delete_dark_press Created with Sketch. deepin-calculator-1.0.2/images/delete_light_hover.svg000066400000000000000000000022331325241207700227320ustar00rootroot00000000000000 delete_hover Created with Sketch. deepin-calculator-1.0.2/images/delete_light_normal.svg000066400000000000000000000022351325241207700231010ustar00rootroot00000000000000 delete_normal Created with Sketch. deepin-calculator-1.0.2/images/delete_light_press.svg000066400000000000000000000022331325241207700227430ustar00rootroot00000000000000 delete_press Created with Sketch. deepin-calculator-1.0.2/images/title_icon.svg000066400000000000000000000054601325241207700212340ustar00rootroot00000000000000 deepin-calculator Created with Sketch. deepin-calculator-1.0.2/math/000077500000000000000000000000001325241207700160415ustar00rootroot00000000000000deepin-calculator-1.0.2/math/cmath.cpp000066400000000000000000000510021325241207700176370ustar00rootroot00000000000000// cmath.cpp // Complex number support : type definition and function for complex numbers. // // This file is part of the SpeedCrunch project // Copyright (C) 2013, 2015-2016 Hadrien Theveneau . // Copyright (C) 2015-2016 Pol Welter. // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "cmath.h" #include "cnumberparser.h" #include "floatconvert.h" #include "hmath.h" #include #include #include #include /** * Creates a new complex number. */ CNumber::CNumber() : real(0) , imag(0) {} /** * Creates a new complex number from one real number */ CNumber::CNumber(const HNumber& hn) : real(hn), imag(0) { } /** * Creates a new complex number from the real and imaginary parts */ CNumber::CNumber(const HNumber& x, const HNumber& y) : real(x) , imag(y) { } /** * Copies from another complex number. */ CNumber::CNumber(const CNumber& cn) : real(cn.real) , imag(cn.imag) { } /** * Creates a new number from an integer value. */ CNumber::CNumber(int i) : real(i) , imag(0) { } /** * Creates a new number from a string. */ CNumber::CNumber(const char* str) { CNumberParser parser(str); parser.parse(this); // FIXME: Exception management. } CNumber::CNumber(const QJsonObject& json) { *this = deSerialize(json); } /** * Returns true if this number is Not a Number (NaN). */ bool CNumber::isNan() const { return real.isNan() || imag.isNan(); } /** * Returns true if this number is zero. */ bool CNumber::isZero() const { return real.isZero() && imag.isZero(); } /** * Returns true if this number is a positive REAL */ bool CNumber::isPositive() const { return real.isPositive() && imag.isZero(); } /** * Returns true if this number is a negative REAL */ bool CNumber::isNegative() const { return real.isNegative() && imag.isZero(); } /** * Returns true if this number is integer and REAL */ bool CNumber::isInteger() const { return real.isInteger() && imag.isZero(); } /** * Returns true if this number is a Gaussian integer */ bool CNumber::isGaussian() const { return real.isInteger() && imag.isInteger(); } /** * Returns true if this number is a real number */ bool CNumber::isReal() const { return imag.isZero(); } /** * Returns true if this number is approximately a real number */ bool CNumber::isNearReal() const { return imag.isNearZero(); } void CNumber::serialize(QJsonObject& json) const { json["value"] = CMath::format(*this, CNumber::Format::Fixed() + CNumber::Format::Precision(DECPRECISION)); } CNumber CNumber::deSerialize(const QJsonObject& json) { CNumber result; if (json.contains("value")) { QString str = json["value"].toString(); str.replace(",", "."); result = CNumber(str.toLatin1().constData()); } return result; } /** * Returns a NaN (Not a Number) with error set to * passed parameter. */ CNumber CMath::nan(Error error) { // We must always ensure that both numbers have the same NaN error. CNumber result; result.real = HMath::nan(error); result.imag = HMath::nan(error); return result; } /** * Returns the error code kept with a NaN. */ Error CNumber::error() const { // real and imag have always the same NaN error. return real.error(); } /** * Assigns from another complex number. */ CNumber& CNumber::operator=(const CNumber& cn) { real = cn.real; imag = cn.imag; return *this; } /** * Adds another complex number. */ CNumber CNumber::operator+(const CNumber& num) const { CNumber result; result.real = real + num.real; result.imag = imag + num.imag; return result; } /** * Adds another complex number. */ CNumber& CNumber::operator+=(const CNumber& num) { return operator=(*this + num); } /** * Subtract from another complex number. */ CNumber operator-(const CNumber& n1, const CNumber& n2) { CNumber result; result.real = n1.real - n2.real; result.imag = n1.imag - n2.imag; return result; } /** * Subtract from another complex number. */ CNumber& CNumber::operator-=(const CNumber& num) { return operator=(*this - num); } /** * Multiplies with another complex number. */ CNumber CNumber::operator*(const CNumber& num) const { CNumber result; result.real = real*num.real - imag*num.imag; result.imag = imag*num.real + real*num.imag; return result; } /** * Multiplies with another REAL number. */ CNumber CNumber::operator*(const HNumber& num) const { CNumber result; result.real = real*num; result.imag = imag*num; return result; } /** * Multiplies with another number. */ CNumber& CNumber::operator*=(const CNumber& num) { return operator=(*this * num); } /** * Divides with another complex number. */ CNumber CNumber::operator/(const CNumber& num) const { if (num.isZero()) return CMath::nan(ZeroDivide); else { CNumber result; HNumber divider = num.real*num.real + num.imag*num.imag; result.real = (real*num.real + imag*num.imag) / divider; result.imag = (imag*num.real - real*num.imag) / divider; return result; } } /** * Divides with another REAL number. */ CNumber CNumber::operator/(const HNumber& num) const { if (num.isZero()) return CMath::nan(ZeroDivide); else return CNumber(real / num, imag / num) ; } /** * Divides with another number. */ CNumber& CNumber::operator/=(const CNumber& num) { return operator=(*this / num); } /** * Returns -1, 0, 1 if n1 is less than, equal to, or more than n2. * Only valid for real numbers, since complex ones are not an ordered field. */ int CNumber::compare(const CNumber& other) const { if (isReal() && other.isReal()) return real.compare(other.real); else return false; // FIXME: Return something better. } /** * Returns true if l is greater than r. */ bool operator>(const CNumber& l, const CNumber& r) { return l.compare(r) > 0; } /** * Returns true if l is less than r. */ bool operator<(const CNumber& l, const CNumber& r) { return l.compare(r) < 0; } /** * Returns true if l is greater than or equal to r. */ bool operator>=(const CNumber& l, const CNumber& r) { return l.compare(r) >= 0; } /** * Returns true if l is less than or equal to r. */ bool operator<=(const CNumber& l, const CNumber& r) { return l.compare(r) <= 0; } /** * Returns true if l is equal to r. */ bool operator==(const CNumber& l, const CNumber& r) { return l.compare(r) == 0; } /** * Returns true if l is not equal to r. */ bool operator!=(const CNumber& l, const CNumber& r) { return l.compare(r) != 0; } /** * Changes the sign. */ CNumber operator-(const CNumber& x) { return CNumber(-x.real, -x.imag); } CNumber::Format::Format() : HNumber::Format() , notation(Format::Notation::Null) { } CNumber::Format::Format(const Format& other) : HNumber::Format(static_cast(other)) , notation(other.notation) { } CNumber::Format::Format(const HNumber::Format& other) : HNumber::Format(other) , notation(Notation::Null) { } CNumber::Format CNumber::Format::operator+(const CNumber::Format& other) const { Format result(HNumber::Format::operator+(static_cast(other))); result.notation = (this->notation != Notation::Null) ? this->notation : other.notation; return result; } CNumber::Format CNumber::Format::Polar() { Format result; result.notation = Format::Notation::Polar; return result; } CNumber::Format CNumber::Format::Cartesian() { Format result; result.notation = Format::Notation::Cartesian; return result; } /** * Returns the constant e (Euler's number). */ CNumber CMath::e() { return CNumber(HMath::e()); } /** * Returns the constant pi. */ CNumber CMath::pi() { return CNumber(HMath::pi()); } /** * Returns the constant phi (golden number). */ CNumber CMath::phi() { return CNumber(HMath::phi()); } /** * Returns the constant i. */ CNumber CMath::i() { return CNumber(0, 1); } // TODO: Improve complex number formatting. /** * Formats the given number as string. */ QString CMath::format(const CNumber& cn, CNumber::Format format) { if (cn.isNan()) return "NaN"; else if (cn.imag.isNearZero()) // Number is real. return HMath::format(cn.real, format); if (format.notation == CNumber::Format::Notation::Polar) { QString strRadius = HMath::format(CMath::abs(cn).real, format); HNumber phase = CMath::phase(cn).real; if (phase.isZero()) return strRadius; QString strPhase = HMath::format(phase, format); return QString("%1 * exp(j*%2)").arg(strRadius).arg(strPhase); } else { QString real_part = cn.real.isZero()? "" : HMath::format(cn.real, format); QString imag_part = ""; QString separator = ""; QString prefix = ""; // TODO: Insert two modes, one for a+jb and one for a+bj. QString postfix = "j"; // TODO: Insert two modes, one for a+bi and one for a+bj. if (cn.imag.isPositive()) { separator = cn.real.isZero() ? "": "+"; imag_part = HMath::format(cn.imag, format); } else { separator = "-"; imag_part = HMath::format(-cn.imag, format); } return real_part + separator + prefix + imag_part + postfix; } } /** * Returns the norm of n. */ CNumber CMath::abs(const CNumber& n) { return HMath::sqrt(n.real * n.real + n.imag * n.imag); } /** * Returns the square root of n. */ CNumber CMath::sqrt(const CNumber& n) { CNumber result; HNumber s = (n.imag.isPositive() || n.imag.isZero()) ? 1 : -1; // cf https://en.wikipedia.org/wiki/Square_root#Square_roots_of_negative_and_complex_numbers. result.real = HMath::sqrt((abs(n).real + n.real) / 2); result.imag = s * HMath::sqrt((abs(n).real - n.real) / 2); return result; } /** * Raises n1 to an integer n. */ CNumber CMath::raise(const CNumber& n1, int n) { return CMath::exp(CMath::ln(n1) * n); } /** * Raises n1 to n2. */ CNumber CMath::raise(const CNumber& n1, const CNumber& n2) { return CMath::exp(CMath::ln(n1) * n2); } /** * Returns e raised to x. */ CNumber CMath::exp(const CNumber& x) { HNumber abs = HMath::exp(x.real); return CNumber(abs*HMath::cos(x.imag), abs*HMath::sin(x.imag)); } /** * Returns the complex natural logarithm of x. */ CNumber CMath::ln(const CNumber& x) { HNumber abs = CMath::abs(x).real; CNumber result; result.real = HMath::ln(abs); // Principal Value logarithm // https://en.wikipedia.org/wiki/Complex_logarithm#Definition_of_principal_value auto imag = HMath::arccos(x.real / abs); result.imag = (x.imag.isPositive() || x.imag.isZero()) ? imag : -imag; return result; } /** * Returns the common logarithm of x. */ CNumber CMath::lg(const CNumber& x) { return CMath::ln(x) / HMath::ln(10); } /** * Returns the binary logarithm of x. */ CNumber CMath::lb(const CNumber& x) { return CMath::ln(x) / HMath::ln(2); } /** * Returns the logarithm of x to base. * If x is non positive, returns NaN. */ CNumber CMath::log(const CNumber& base, const CNumber& x) { return CMath::ln(x) / CMath::ln(base); } /** * Returns the complex sine of x. Note that x must be in radians. */ CNumber CMath::sin(const CNumber& x) { // cf. https://en.wikipedia.org/wiki/Sine#Sine_with_a_complex_argument. return CNumber(HMath::sin(x.real) * HMath::cosh(x.imag), HMath::cos(x.real) * HMath::sinh(x.imag)); } /** * Returns the cosine of x. Note that x must be in radians. */ CNumber CMath::cos(const CNumber& x) { // Expanded using Wolfram Mathematica 9.0. return CNumber(HMath::cos(x.real) * HMath::cosh(x.imag), -HMath::sin(x.real) * HMath::sinh(x.imag)); } /** * Returns the tangent of x. Note that x must be in radians. */ CNumber CMath::tan(const CNumber& x) { return CMath::sin(x) / CMath::cos(x); } /** * Returns the hyperbolic sine of x. */ CNumber CMath::sinh(const CNumber& x) { return (exp(x) - exp(-x)) / HNumber(2); } /** * Returns the hyperbolic cosine of x. */ CNumber CMath::cosh(const CNumber& x) { return (exp(x) + exp(-x)) / HNumber(2); } /** * Returns the hyperbolic tangent of x. */ CNumber CMath::tanh(const CNumber& x) { return sinh(x) / cosh(x); } /** * Returns the cotangent of x. Note that x must be in radians. */ CNumber CMath::cot(const CNumber& x) { return cos(x) / sin(x); } /** * Returns the secant of x. Note that x must be in radians. */ CNumber CMath::sec(const CNumber& x) { return CNumber(1) / cos(x); } /** * Returns the cosecant of x. Note that x must be in radians. */ CNumber CMath::csc(const CNumber& x) { return CNumber(1) / sin(x); } /** * Returns the area hyperbolic sine of x. */ CNumber CMath::arsinh(const CNumber& x) { return CMath::ln(x + CMath::sqrt(x * x + CNumber(1))); } /** * Returns the area hyperbolic cosine of x. */ CNumber CMath::arcosh(const CNumber& x) { return CMath::ln(x + CMath::sqrt(x + CNumber(1)) * CMath::sqrt(x - CNumber(1))); } /** * Returns the area hyperbolic tangent of x. */ CNumber CMath::artanh(const CNumber& x) { return (CNumber("0.5") * CMath::ln(CNumber(1) + x)) - (CNumber("0.5") * CMath::ln(CNumber(1) - x)); } /** * Returns the phase of x. */ CNumber CMath::phase(const CNumber& x) { return HMath::arctan2(x.real, x.imag); } /** * Returns the arc tangent of x. */ CNumber CMath::arctan(const CNumber& x) { return CMath::i() * (CMath::ln(CNumber(1) - CMath::i() * x) - CMath::ln(CNumber(1) + CMath::i() * x)) / 2; } /** * Returns the arc sine of x. */ CNumber CMath::arcsin(const CNumber& x) { return -CMath::i() * CMath::ln(CMath::i() * x + sqrt(CNumber(1) - x * x)); } /** * Returns the arc cosine of x. */ CNumber CMath::arccos(const CNumber& x) { return -CMath::i() * CMath::ln(x + sqrt(x * x - CNumber(1))); } // Wrappers towards functions defined only on real numbers // ======================================================= // NaN is treated like real numbers for the purposes of wrappers. #define ENSURE_REAL(number, error) \ if((number).isNan() || !(number).isNearReal()) \ return CMath::nan(error); #define REAL_WRAPPER_CNUMBER_1(fct, error) \ CNumber CNumber::fct() const \ { \ ENSURE_REAL(*this, error); \ return CNumber(this->real.fct()); \ } #define REAL_WRAPPER_CNUMBER_2(fct, error) \ CNumber CNumber::fct(const CNumber& x) const \ { \ ENSURE_REAL(*this, error); \ ENSURE_REAL(x, error); \ return CNumber(this->real.fct(x.real)); \ } #define REAL_WRAPPER_CNUMBER_3(fct, error) \ CNumber& CNumber::fct(const CNumber& x) \ { \ if(!this->isReal()) { \ *this = CMath::nan(error); \ return *this; \ } \ if (!x.isReal()) { \ *this = CMath::nan(error); \ return *this; \ } \ this->real.fct(x.real); \ return *this; \ } #define REAL_WRAPPER_CNUMBER_4(fct, error) \ int CNumber::fct() const \ { \ if (!this->isNearReal()) \ return 0; /* FIXME: Better fail value. */ \ return this->real.fct(); \ } #define REAL_WRAPPER_CMATH_NUM(fct, error) \ CNumber CMath::fct(const CNumber& x) \ { \ ENSURE_REAL(x, error); \ return CNumber(HMath::fct(x.real)); \ } #define REAL_WRAPPER_CMATH_NUM_NUM(fct, error) \ CNumber CMath::fct(const CNumber& x1, const CNumber& x2) \ { \ ENSURE_REAL(x1, error); \ ENSURE_REAL(x2, error); \ return CNumber(HMath::fct(x1.real, x2.real)); \ } #define REAL_WRAPPER_CMATH_NUM_INT(fct, error) \ CNumber CMath::fct(const CNumber& x1, int n) \ { \ ENSURE_REAL(x1, error); \ return CNumber(HMath::fct(x1.real, n)); \ } #define REAL_WRAPPER_CMATH_NUM_NUM_NUM(fct, error) \ CNumber CMath::fct(const CNumber& x1, const CNumber& x2, const CNumber& x3) \ { \ ENSURE_REAL(x1, error); \ ENSURE_REAL(x2, error); \ ENSURE_REAL(x3, error); \ return CNumber(HMath::fct(x1.real, x2.real, x3.real)); \ } #define REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(fct, error) \ CNumber CMath::fct(const CNumber& x1, const CNumber& x2, const CNumber& x3, const CNumber& x4) \ { \ ENSURE_REAL(x1, error); \ ENSURE_REAL(x2, error); \ ENSURE_REAL(x3, error); \ ENSURE_REAL(x4, error); \ return CNumber(HMath::fct(x1.real, x2.real, x3.real, x4.real)); \ } // CNumber REAL_WRAPPER_CNUMBER_4(toInt, OutOfDomain) REAL_WRAPPER_CNUMBER_2(operator%, OutOfDomain) REAL_WRAPPER_CNUMBER_2(operator&, OutOfLogicRange) REAL_WRAPPER_CNUMBER_3(operator&=, OutOfLogicRange) REAL_WRAPPER_CNUMBER_2(operator|, OutOfLogicRange) REAL_WRAPPER_CNUMBER_3(operator|=, OutOfLogicRange) REAL_WRAPPER_CNUMBER_2(operator^, OutOfLogicRange) REAL_WRAPPER_CNUMBER_3(operator^=, OutOfLogicRange) REAL_WRAPPER_CNUMBER_1(operator~, OutOfLogicRange) REAL_WRAPPER_CNUMBER_2(operator>>, OutOfLogicRange) REAL_WRAPPER_CNUMBER_2(operator<<, OutOfLogicRange) // CMath GENERAL MATH REAL_WRAPPER_CMATH_NUM(rad2deg, OutOfDomain) REAL_WRAPPER_CMATH_NUM(deg2rad, OutOfDomain) REAL_WRAPPER_CMATH_NUM(integer, OutOfDomain) REAL_WRAPPER_CMATH_NUM(frac, OutOfDomain) REAL_WRAPPER_CMATH_NUM(floor, OutOfDomain) REAL_WRAPPER_CMATH_NUM(ceil, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(gcd, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(idiv, OutOfDomain) REAL_WRAPPER_CMATH_NUM_INT(round, OutOfDomain) REAL_WRAPPER_CMATH_NUM_INT(trunc, OutOfDomain) REAL_WRAPPER_CMATH_NUM(cbrt, OutOfDomain) REAL_WRAPPER_CMATH_NUM(sgn, OutOfDomain) // CMath EXPONENTIAL FUNCTION AND RELATED REAL_WRAPPER_CMATH_NUM_NUM(arctan2, OutOfDomain) // CMath TRIGONOMETRY /* All trigonometry functions accept complex numbers */ // CMath HIGHER MATH FUNCTIONS REAL_WRAPPER_CMATH_NUM_NUM(factorial, NotImplemented) REAL_WRAPPER_CMATH_NUM(erf, OutOfDomain) REAL_WRAPPER_CMATH_NUM(erfc, OutOfDomain) REAL_WRAPPER_CMATH_NUM(gamma, NotImplemented) REAL_WRAPPER_CMATH_NUM(lnGamma, NotImplemented) // CMath PROBABILITY REAL_WRAPPER_CMATH_NUM_NUM(nCr, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(nPr, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM(binomialPmf, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM(binomialCdf, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(binomialMean, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(binomialVariance, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(hypergeometricPmf, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(hypergeometricCdf, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM(hypergeometricMean, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM(hypergeometricVariance, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(poissonPmf, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM(poissonCdf, OutOfDomain) REAL_WRAPPER_CMATH_NUM(poissonMean, OutOfDomain) REAL_WRAPPER_CMATH_NUM(poissonVariance, OutOfDomain) // CMath LOGIC REAL_WRAPPER_CMATH_NUM_NUM(mask, OutOfLogicRange) REAL_WRAPPER_CMATH_NUM_NUM(sgnext, OutOfLogicRange) REAL_WRAPPER_CMATH_NUM_NUM(ashr, OutOfLogicRange) // CMath IEEE-754 CONVERSION REAL_WRAPPER_CMATH_NUM_NUM_NUM(decodeIeee754, OutOfDomain) REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(decodeIeee754, OutOfDomain) CNumber CMath::encodeIeee754(const CNumber& val, const CNumber& exp_bits, const CNumber& significand_bits, const CNumber& exp_bias) { ENSURE_REAL(exp_bits, OutOfDomain); ENSURE_REAL(significand_bits, OutOfDomain); ENSURE_REAL(exp_bias, OutOfDomain); if (!val.isNan() && !val.isNearReal()) return CMath::nan(OutOfDomain); return CNumber(HMath::encodeIeee754(val.real, exp_bits.real, significand_bits.real, exp_bias.real)); } CNumber CMath::encodeIeee754(const CNumber& val, const CNumber& exp_bits, const CNumber& significand_bits) { ENSURE_REAL(exp_bits, OutOfDomain); ENSURE_REAL(significand_bits, OutOfDomain); if (!val.isNan() && !val.isNearReal()) return CMath::nan(OutOfDomain); return CNumber(HMath::encodeIeee754(val.real, exp_bits.real, significand_bits.real)); } deepin-calculator-1.0.2/math/cmath.h000066400000000000000000000203151325241207700173070ustar00rootroot00000000000000// cmath.h // Complex number support : type definition and function for complex numbers. // // This file is part of the SpeedCrunch project // Copyright (C) 2013, 2015-2016 Hadrien Theveneau . // Copyright (C) 2015-2016 Pol Welter. // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef MATH_CMATH_H #define MATH_CMATH_H #include "hmath.h" #include "rational.h" #include #include class CMath; class CNumber { friend class CMath; friend CNumber operator-(const CNumber&); friend CNumber operator-(const CNumber&, const CNumber&); friend bool operator>(const CNumber&, const CNumber&); friend bool operator<(const CNumber&, const CNumber&); friend bool operator>=(const CNumber&, const CNumber&); friend bool operator<=(const CNumber&, const CNumber&); friend bool operator==(const CNumber&, const CNumber&); friend bool operator!=(const CNumber&, const CNumber&); public: CNumber(); CNumber(const HNumber&); CNumber(const HNumber&, const HNumber&); CNumber(const CNumber&); CNumber(int); CNumber(const char*); CNumber(const QJsonObject&); ~CNumber() { } bool isNan() const; bool isZero() const; bool isPositive() const; bool isNegative() const; bool isInteger() const; bool isGaussian() const; bool isReal() const; bool isNearReal() const; void serialize(QJsonObject&) const; static CNumber deSerialize(const QJsonObject&); int toInt() const; // Removed, too problematic for complex numbers. Error error() const; CNumber& operator=(const CNumber&); CNumber operator+(const CNumber&) const; CNumber& operator+=(const CNumber&); CNumber& operator-=(const CNumber&); CNumber operator*(const CNumber&) const; CNumber operator*(const HNumber&) const; CNumber operator*(int x) { return operator * (HNumber(x)); } // Overload ambiguity resolution. CNumber& operator*=(const CNumber&); CNumber operator/(const CNumber&) const; CNumber operator/(const HNumber&) const; CNumber operator/(int x) { return operator / (HNumber(x)); } // Overload ambiguity resolution. CNumber& operator/=(const CNumber&); CNumber operator%(const CNumber&) const; CNumber operator&(const CNumber&) const; CNumber& operator&=(const CNumber&); CNumber operator|(const CNumber&) const; CNumber& operator|=(const CNumber&); CNumber operator^(const CNumber&) const; CNumber& operator^=(const CNumber&); CNumber operator~() const; CNumber operator>>(const CNumber&) const; CNumber operator<<(const CNumber&) const; private: int compare(const CNumber&) const; public: HNumber real; HNumber imag; // FIXME: Better access control to real and imag. // Invariants: // - real and imag are neither or both NaN. // - real and imag have the same NaN error. struct Format : public HNumber::Format { enum class Notation {Null, Cartesian, Polar}; Notation notation; Format(); Format(const Format&); Format(const HNumber::Format&); Format operator+(const Format&) const; static Format Polar(); static Format Cartesian(); }; }; class CMath { public: // FORMAT static QString format(const CNumber&, CNumber::Format = CNumber::Format()); // CONSTANTS static CNumber e(); static CNumber phi(); static CNumber pi(); static CNumber nan(Error error = Success); static CNumber i(); // GENERAL MATH static CNumber rad2deg(const CNumber&); static CNumber deg2rad(const CNumber&); static CNumber abs(const CNumber&); static CNumber integer(const CNumber&); static CNumber frac(const CNumber&); static CNumber floor(const CNumber&); static CNumber ceil(const CNumber&); static CNumber gcd(const CNumber&, const CNumber&); static CNumber idiv(const CNumber&, const CNumber&); static CNumber round(const CNumber&, int prec = 0); static CNumber trunc(const CNumber&, int prec = 0); static CNumber sqrt(const CNumber&); static CNumber cbrt(const CNumber&); static CNumber raise(const CNumber&, int); static CNumber raise(const CNumber&, const CNumber&); static CNumber sgn(const CNumber&); // EXPONENTIAL FUNCTION AND RELATED static CNumber exp(const CNumber&); static CNumber ln(const CNumber&); static CNumber lg(const CNumber&); static CNumber lb(const CNumber&); static CNumber log(const CNumber& base, const CNumber& x); static CNumber sinh(const CNumber&); static CNumber cosh(const CNumber&); static CNumber tanh(const CNumber&); static CNumber arsinh(const CNumber&); static CNumber arcosh(const CNumber&); static CNumber artanh(const CNumber&); // COMPLEX SPECIFIC static CNumber real(const CNumber& x) {return x.real;} static CNumber imag(const CNumber& x) {return x.imag;} static CNumber phase(const CNumber&); // TRIGONOMETRY static CNumber sin(const CNumber&); static CNumber cos(const CNumber&); static CNumber tan(const CNumber&); static CNumber cot(const CNumber&); static CNumber sec(const CNumber&); static CNumber csc(const CNumber&); static CNumber arcsin(const CNumber&); static CNumber arccos(const CNumber&); static CNumber arctan(const CNumber&); static CNumber arctan2(const CNumber&, const CNumber&); // HIGHER MATH FUNCTIONS static CNumber factorial(const CNumber&, const CNumber& base = CNumber(1)); static CNumber gamma(const CNumber&); static CNumber lnGamma(const CNumber&); static CNumber erf(const CNumber&); static CNumber erfc(const CNumber&); // PROBABILITY static CNumber nCr(const CNumber&, const CNumber&); static CNumber nPr(const CNumber&, const CNumber&); static CNumber binomialPmf(const CNumber& k, const CNumber& n, const CNumber& p); static CNumber binomialCdf(const CNumber& k, const CNumber& n, const CNumber& p); static CNumber binomialMean(const CNumber& n, const CNumber& p); static CNumber binomialVariance(const CNumber& n, const CNumber& p); static CNumber hypergeometricPmf(const CNumber& k, const CNumber& N, const CNumber& M, const CNumber& n); static CNumber hypergeometricCdf(const CNumber& k, const CNumber& N, const CNumber& M, const CNumber& n); static CNumber hypergeometricMean(const CNumber& N, const CNumber& M, const CNumber& n); static CNumber hypergeometricVariance(const CNumber& N, const CNumber& M, const CNumber& n); static CNumber poissonPmf(const CNumber& k, const CNumber& l); static CNumber poissonCdf(const CNumber& k, const CNumber& l); static CNumber poissonMean(const CNumber& l); static CNumber poissonVariance(const CNumber& l); // LOGIC static CNumber mask(const CNumber&, const CNumber& bits); static CNumber sgnext(const CNumber&, const CNumber& bits); static CNumber ashr(const CNumber&, const CNumber& bits); // IEEE-754 CONVERSION static CNumber decodeIeee754(const CNumber&, const CNumber& exp_bits, const CNumber& significand_bits); static CNumber decodeIeee754(const CNumber&, const CNumber& exp_bits, const CNumber& significand_bits, const CNumber& exp_bias); static CNumber encodeIeee754(const CNumber&, const CNumber& exp_bits, const CNumber& significand_bits); static CNumber encodeIeee754(const CNumber&, const CNumber& exp_bits, const CNumber& significand_bits, const CNumber& exp_bias); }; std::ostream& operator<<(std::ostream&, const CNumber&); #endif // CMATH_CMATH_H deepin-calculator-1.0.2/math/cnumberparser.cpp000066400000000000000000000077051325241207700214260ustar00rootroot00000000000000// cnumberparser.cpp // Complex number support : complex number parser using a recursive // descent approach. // // This file is part of the SpeedCrunch project // Copyright (C) 2013, 2015-2016 Hadrien Theveneau . // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. // This complex number parser currently recognizes the following forms : // // a // a+ib // a+jb // a+bi // a+bj // ib // jb // bi // bj // // The grammar describing one complex number is: // // complex_number -> part suite // suite -> [] // suite -> + part suite // // part -> prefixed_part // part -> postfixed_part // // part_prefixed -> i base_number // part_prefixed -> j base_number // // part_postfixed -> base_number postfix // // postfix -> i // postfix -> j // postfix -> [] #include "cnumberparser.h" using namespace CNumberParserExceptions; CNumberParser::CNumberParser(const char * _str) : str(_str) { } /* Parses a complex number using a recursive-desent approach. * * If successfull, stores the result into *Number. * * See header file for details. */ void CNumberParser::parse (CNumber * Number) { /* Parsing */ CNumber a = part(); CNumber b = suite(); /* Processing */ *Number = a + b; } /* Null string or empty string. strlen(NULL) is undefined. */ static char _isempty(const char* p){ return p == NULL || *p == '\0'; } /* Parsing functions. * * Each of the following function parses one producion of the grammar */ CNumber CNumberParser::part () { if (_isempty(str)) { return CMath::nan(); } else if (strncmp(str, "NaN", 3) == 0) { return CMath::nan(); } else if (*str == 'i' || *str == 'j') { return part_prefixed(); } else if (isdigit (*str) || *str == '-' || *str == '+' || *str == '.') { /* Example cases : 1.0 -1.0 +1.0 .5 */ return part_postfixed(); } else { return CMath::nan(); } } CNumber CNumberParser::suite () { if (_isempty(str)) { return CNumber(0); } else if (*str == '+') { accept(); CNumber a = part(); CNumber b = suite(); return a + b; } else if (*str == '-') { accept(); CNumber a = part(); CNumber b = suite(); return (-a) + b; } else { return CNumber(0); } } CNumber CNumberParser::part_prefixed () { if (*str == 'i' || *str == 'j') { /* Parsing */ accept(); HNumber y = base_number(); /* Processing */ HNumber x = HNumber(0); CNumber res = CNumber(x, y); return res; } else { throw UnexpectedSymbol(*str); } } HNumber CNumberParser::base_number () { /* FIXME ! Error checking ! */ HNumber x = HMath::parse_str(str, &str); return x; } CNumber CNumberParser::part_postfixed () { /* Parsing */ HNumber x = base_number(); postfix_t p = postfix(); /* Processing */ if (p == REAL) /* If real part of a complex number */ return CNumber(x, 0); else if (p == IMAG) /* If imaginary part */ return CNumber(0, x); else { /* Should never happen */ throw LogicError(); } } CNumberParser::postfix_t CNumberParser::postfix () { if (*str == 'i' || *str == 'j') { accept(); return IMAG; } else { return REAL; } } deepin-calculator-1.0.2/math/cnumberparser.h000066400000000000000000000050711325241207700210650ustar00rootroot00000000000000// cnumberparser.h // Complex number support : complex number parser using a recursive // descent approach. // // This file is part of the SpeedCrunch project // Copyright (C) 2013, 2015-2016 Hadrien Theveneau . // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. // This complex number parser currently recognizes the following forms : // // a // a+ib // a+jb // a+bi // a+bj // ib // jb // bi // bj // // The grammar describing one complex number is: // // complex_number -> part suite // suite -> [] // suite -> + part suite // // part -> prefixed_part // part -> postfixed_part // // part_prefixed -> i base_number // part_prefixed -> j base_number // // part_postfixed -> base_number postfix // // postfix -> i // postfix -> j // postfix -> [] #ifndef CNUMBER_PARSER_HXX #define CNUMBER_PARSER_HXX #include #include #include "hmath.h" #include "cmath.h" class CNumberParser { private: const char * str; /* Remaining of the string to parse */ /* Parsing functions. */ void accept () {str++;} /* Each of the following function parses one producion of the grammar. */ CNumber part (); CNumber suite (); CNumber part_prefixed (); HNumber base_number (); CNumber part_postfixed (); typedef enum {IMAG, REAL} postfix_t; postfix_t postfix (); public: CNumberParser (const char * _str); void parse (CNumber * number); }; namespace CNumberParserExceptions { class Exception : public std::exception {}; class UnexpectedSymbol : public Exception { private: char symbol; public: char get_symbol () {return symbol;} UnexpectedSymbol (char _symbol) : symbol(_symbol) {} /* FIXME ! Error message ! */ }; class LogicError : Exception {}; class UnexpectedEnd : public Exception {}; } #endif // CNUMBER_PARSER_HXX deepin-calculator-1.0.2/math/floatcommon.c000066400000000000000000000233241325241207700205270ustar00rootroot00000000000000/* floatcommon.c: convenience functions, based on floatnum. */ /* Copyright (C) 2007 - 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatcommon.h" #include "floatconst.h" #include "floatlong.h" #include #include #define MSB (1 << (sizeof(unsigned)*8 - 1)) #define LOGMSB ((301*(sizeof(unsigned)*8-1))/1000) static char _chckparam1( cfloatnum x, int digits, int limit, int specialval) { if (float_isnan(x)) { float_seterror(NoOperand); return 0; } if ((digits <= 0 || digits > limit) && digits != specialval) { float_seterror(InvalidPrecision); return 0; } return 1; } static char _chckparam( floatnum x, int digits, int limit, int specialval) { if (!_chckparam1(x, digits, limit, specialval)) return _setnan(x); return 1; } char chckmathparam( floatnum x, int digits) { return _chckparam(x, digits, MATHPRECISION, 1); } int logexp( cfloatnum x) { int expx, result; expx = float_getexponent(x); if (expx < 0) expx = -expx; result = -1; while (expx != 0) { expx <<= 1; ++result; } return result; } void float_setasciiz( floatnum x, const char* asciiz) { float_setscientific(x, asciiz, NULLTERMINATED); } char float_divi( floatnum quotient, cfloatnum dividend, int divisor, int digits) { floatstruct tmp; int result, expx; if (!_chckparam1(dividend, digits, maxdigits, INTQUOT)) return _setnan(quotient); if (digits != INTQUOT && (divisor == 1 || divisor == -1)) return float_muli(quotient, dividend, divisor, digits); if (divisor == 10 || divisor == -10) { expx = float_getexponent(dividend)-1; if (expx < -float_getrange() - 1) return _seterror(quotient, Underflow); } float_create(&tmp); float_setinteger(&tmp, divisor); result = float_div(quotient, dividend, &tmp, digits); float_free(&tmp); return result; } char float_addi( floatnum sum, cfloatnum summand1, int summand2, int digits) { floatstruct tmp; int result; if (!_chckparam1(summand1, digits, maxdigits, EXACT)) return _setnan(sum); if (summand2 == 0) return float_copy(sum, summand1, digits); float_create(&tmp); float_setinteger(&tmp, summand2); result = float_add(sum, summand1, &tmp, digits); float_free(&tmp); return result; } char float_muli( floatnum product, cfloatnum factor1, int factor2, int digits) { floatstruct tmp; int result; int expx; if (!_chckparam1(factor1, digits, maxdigits, EXACT)) return _setnan(product); switch(factor2) { case 0: return _setzero(product); case 1: case -1: case 10: case -10: expx = float_getexponent(factor1); if (factor2 != 1 && factor2 != -1 && ++expx > float_getrange()) return _seterror(product, Overflow); result = float_copy(product, factor1, digits); if (factor2 < 0) float_neg(product); float_setexponent(product, expx); return result; case 2: case -2: result = float_add(product, factor1, factor1, digits); if (factor2 < 0) float_neg(product); return result; } float_create(&tmp); float_setinteger(&tmp, factor2); result = float_mul(product, factor1, &tmp, digits); float_free(&tmp); return result; } int leadingdigits( cfloatnum x, int digits) { int i; unsigned tmp, ovfl; char buf[LOGMSB+1]; const unsigned msb = MSB; if (digits <= 0 || digits > (int)LOGMSB+1 || float_isnan(x) || float_iszero(x)) return 0; memset(buf, '0', digits); float_getsignificand(buf, digits, x); tmp = 0; for(i = 0; i < digits; ++i) { ovfl = 10; if (_longmul(&tmp, &ovfl)) { ovfl = buf[i] - '0'; _longadd(&tmp, &ovfl); } if (ovfl != 0) return 0; } if (float_getsign(x) < 0) { if (tmp > msb) return 0; if (tmp == msb) return (int)tmp; return -(int)tmp; } if (tmp >= msb) return 0; return (int)tmp; } int float_abscmp( floatnum x, floatnum y) { signed char sx, sy; int result; sx = float_getsign(x); sy = float_getsign(y); float_abs(x); float_abs(y); result = float_cmp(x, y); float_setsign(x, sx); float_setsign(y, sy); return result; } int float_relcmp( floatnum x, floatnum y, int digits) { /* do not simply use float_sub, because of overflow/underflow */ floatstruct tmp; int result; int expx, expy, expdiff; result = float_cmp(x, y); if (result == 0 || float_getlength(x) == 0 || float_getlength(y) == 0 || float_getsign(x) != float_getsign(y)) return result; expx = float_getexponent(x); expy = float_getexponent(y); expdiff = expx - expy; if (expdiff >= 2 || expdiff < -2) return result; float_create(&tmp); if (result > 0) float_setexponent(x, 0); float_setexponent(y, expy - expx); float_sub(&tmp, x, y, 2); if ((result * float_getsign(x)) > 0) float_div(&tmp, &tmp, x, 2); else float_div(&tmp, &tmp, y, 2); if (float_getexponent(&tmp) < -digits) result = 0; float_setexponent(x, expx); float_setexponent(y, expy); float_free(&tmp); return result; } char float_reciprocal( floatnum x, int digits) { return float_div(x, &c1, x, digits); } char float_isinteger( cfloatnum x) { return !float_isnan(x) && float_getlength(x) <= float_getexponent(x) + 1; } int float_asinteger( cfloatnum x) { return leadingdigits(x, float_getexponent(x)+1); } void float_checkedround( floatnum x, int digits) { floatstruct tmp; int saveerr; saveerr = float_geterror(); float_create(&tmp); if (float_round(&tmp, x, digits, TONEAREST)) float_move(x, &tmp); float_free(&tmp); float_geterror(); float_seterror(saveerr); } void float_addexp( floatnum x, int smd) { float_setexponent(x, float_getexponent(x) + smd); } char float_isodd( floatnum x) { return (float_getdigit(x, float_getexponent(x)) & 1) != 0; } char float_roundtoint( floatnum x, roundmode mode) { signed char value = 0; signed char sign; char digit; if (float_isnan(x)) return float_int(x); /* sets float_error */ if (float_getexponent(x) >= 0) return float_round(x, x, float_getexponent(x) + 1, mode); sign = float_getsign(x); switch (mode) { case TONEAREST: digit = float_getdigit(x, 0); if (digit < 5 || (digit == 5 && float_getlength(x) == 1)) value = 0; else value = sign; break; case TOINFINITY: value = sign; break; case TOPLUSINFINITY: value = sign > 0? 1 : 0; break; case TOMINUSINFINITY: value = sign > 0? 0 : -1; break; case TOZERO: value = 0; break; } switch (value) { case 0: float_setzero(x); break; case 1: float_copy(x, &c1, EXACT); break; case -1: float_copy(x, &cMinus1, EXACT); break; } return 1; } static float _ipwr(float x, int exp){ int e = exp < 0? -exp : exp; double pwr = x; if ((e & 1) == 0) x = 1; while (e >>= 1){ pwr *= pwr; if ((exp & 1) != 0) x *= pwr; } return exp < 0? 1/x : x; } /* returns x as a float. Only the first 6 digits contribute to the result. The exponent has to be in the valid range of a float */ float float_asfloat(cfloatnum x){ return leadingdigits(x, 6)/100000.0 * _ipwr(10, float_getexponent(x)); } void float_setfloat(floatnum dest, float x){ int exp = aprxlog10(x); // use two assignments to avoid overflow x *= _ipwr(10, -exp); x *= 100000000; float_setinteger(dest, (int)x); float_addexp(dest, exp - 8); } /* Somehow math.h cannot always be included with the full set of ISO C99 math functions enabled. So use the approximations below. These functions are used to get first guess start values for iterative algorithms, or to estimate round off errors, or to find the approximative size of a summand. They need not be accurate to more than, say, 0.1% */ float aprxsqrt(float x){ int exp, i; float x2 = 2 * frexp(x, &exp) - 1; float result = (0.5 - 0.125 * x2) * x2 + 1; x2 += 1; for (i = 0; ++i <= 2;) result = 0.5 * (result + x2 / result); if ((exp & 1) == 0) result *= M_SQRT2; return result * _ipwr(2, (exp - 1) >> 1); } float aprxln(float x){ /* The evaluation of approxlog(x) is based on an approximation suggested by Abramowitz, Stegun, Handbook of mathematical functions. The returned logarithm is valid to 5 (decimal) digits after the decimal point. */ int exp; x = 2 * frexpf(fabs(x), &exp) - 1; return ((((0.03215845 * x - 0.13606275) * x + 0.28947478) * x - 0.49190896) * x + 0.99949556) * x + (exp - 1) * M_LN2; } float aprxlog2(float x){ return aprxln(x) * M_LOG2E; } float aprxlog10(float x){ return aprxln(x) * M_LOG10E; } float aprxlog10fn(cfloatnum x){ return float_getexponent(x) + aprxlog10(leadingdigits(x, 5)) - 4; } float aprxlngamma(float x){ return (x-0.5) * aprxln(x) - x + 0.9189385332f; } deepin-calculator-1.0.2/math/floatcommon.h000066400000000000000000000101161325241207700205270ustar00rootroot00000000000000/* floatcommon.h: header file for convenience functions, based on floatnum. */ /* Copyright (C) 2007 - 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATCOMMON_H # define FLOATCOMMON_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif /* helper, checks parameters. Sets float_error to NaNOperand or InvalidPrecision and sets to NaN, if the parameters do not meet the requirements of routines for higher mathematical functions, and returns 0 in this case */ char chckmathparam(floatnum x, int digits); /* helper, determines, how many decimal digits the exponent of has. If the exponent is 0, -1 is returned */ int logexp(cfloatnum x); /* helper, returns the first decimal digits and the sign of a significand, encoded in an integer. */ int leadingdigits(cfloatnum x, int digits); /* convenience wrapper for float_setscientific, setting the last parameter to NULLTERMINATED */ void float_setasciiz(floatnum x, const char* asciiz); /* convenience wrapper for float_add, adds a signed integer to and places the result in */ char float_addi(floatnum sum, cfloatnum summand1, int summand2, int digits); /* convenience wrapper for float_mul, multiplies a signed integer with and places the result in */ char float_muli(floatnum product, cfloatnum factor1, int factor2, int digits); /* convenience wrapper for float_div, divides by a signed integer and places the result in */ char float_divi(floatnum quotient, cfloatnum dividend, int divisor, int digits); /* convenience wrapper for float_cmp: compares the absolute value of both operands */ int float_abscmp(floatnum x, floatnum y); /* convenience wrapper for float_div, returns 1/ */ char float_reciprocal(floatnum x, int digits); /* compares two numbers in a normal fashion, but returns equal, if their relative difference is less than 1e-, i.e. |(x-y)/max(x,y)| < 1e- */ int float_relcmp(floatnum x, floatnum y, int digits); /* returns whether x is an integer */ char float_isinteger(cfloatnum x); /* returns the integer part of x as integer. If x exceeds the integer range, 0 is returned */ int float_asinteger(cfloatnum x); /* rounds x in TONEAREST mode. If x overflows, the rounding is reverted. Does not report errors */ void float_checkedround(floatnum x, int digits); /* a fast way to multiply with a power of ten, does not set float_error on overflow or NaN, returns silently NaN instead*/ void float_addexp(floatnum x, int smd); /* returns 0, if the integer part of x is even */ char float_isodd(floatnum x); /* an extension of float_int: you can choose the round mode errors: FLOAT_NANOPERAND FLOAT_OVERFLOW (if EXP_MAX is really small) */ char float_roundtoint(floatnum x, roundmode mode); float float_asfloat(cfloatnum x); void float_setfloat(floatnum dest, float x); float aprxsqrt(float x); float aprxln(float x); float aprxlog10(float x); float aprxlog2(float x); float aprxlngamma(float x); float aprxlog10fn(cfloatnum x); #ifdef __cplusplus } #endif #endif /* FLOATCOMMON_H */ deepin-calculator-1.0.2/math/floatconfig.h000066400000000000000000000157061325241207700205160ustar00rootroot00000000000000/* floatdefines.h: basic settings in floatnum. */ /* Copyright (C) 2007 - 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ /* this file contains the basic settings, that control the overall behaviour of floatnum and derivates. Uncomment or set any of the following defines according to your needs. */ #ifndef _FLOATCONFIG_H #define _FLOATCONFIG_H /* FLOATDEBUG introduces some extensions to floatnum, so you can easily follow operations of floatnum in a debugger like ddd. Uncomment this, if you develop code based on floatnum, and if you want to look into floatnum variables during a debugger session. */ // #define FLOATDEBUG /* enables a pre-defined set of macros so that a regression test suite of floatnum can be executed. These settings are such that corner cases can easily be triggered. The settings are not useful in a real application of floatnum. Uncomment this if you want to run the standard regression test suite of floatnum */ // #define _FLOATNUMTEST /* floatnum uses bc's bc_num format to store and operate on data. Since bc_num is an arbitrary precision format, operands may grow to extreme sizes, where complex operations take considerable time to execute, up to an hour or more. floatconfig defines a guard value to avoid extreme long operands. Any request to produce a result of more than MAXDIGITS digits is considered an error and yields a NaN result. When setting this value, bear in mind, this is a global value that effects internal operations as well as 'user' requests. When using the routines for transcendent mathematical functions, you should allow extra 14 digits, so that operations like float_exp do not fail when they compute something near maximum precision. */ #define MAXDIGITS 250 /* the number of bits into which an exponent of a floatnum is encoded. In order to avoid integer overflow, this should be at least two bits less than the bits in the integer type chosen for the exponent. The default is two bit less than the size of an int */ // #define BITS_IN_EXP 30 /* floatnum puts an upper limit on the base 10 exponent of its numbers that is based on the size of an integer, but even for 16 bit integers this limit is as big as 4095. Real applications usually do not need such big numbers. If you want to limit the range of possible numbers, set this value accordingly. An operation result exceeding this limit is converted into a NaN, and an overflow/underflow is reported. The default is the maximum positive value that can be encoded in BITS_IN_EXP bits. If you change EXPMAX, you might want to reduce BITS_IN_EXP as well. */ /* #define EXPMAX 5000 */ /* The precision of basic operations like + or * is limited by MAXDIGITS. In addition, some higher mathematical functions involve constants, that, of course, are stored to a limited precision only. This puts another bound on floatnum, described by the value MATHPRECISION. Since procedures for higher mathematical functions employ basic operations to determine their result, MATHPRECISION is <= MAXDIGITS. The current math library version of floatnum limits higher mathematical functions to 100 digits precision. One can say, MATHPRECISION describes the granularity of the number space, because higher functions do not (reliably) produce different results for values closer to each other than this granularity. You may re-define granularity by setting DECPRECISION. This will never bypass MATHPRECISION, being always the limit for the math library, but basic operations may benefit from finer granularity, up to the overall limit MAXDIGITS. If you lower granularity, that saves some memory and evaluation time in a few places. Granularity means that integers with more than DECPRECISION digits might not be saved without loss of digits. So DECPRECISION defines the integer range of floatnum. Because base convertion and logic operations are integer based, both are limited by DECPRECISION as well. By default, DECPRECISION is set to MATHPRECISION */ #define DECPRECISION 78 /* The integer domain of logical functions is a true subset of the integer range, because, according to their nature, they operate modulo a power of two, so the limit on their input is best chosen to be a power of 2. If you do not declare a limit here, an appropriate value is derived from DECPRECISION. If you change this value, make sure 2^LOGICRANGE is less than 10^DECPRECISION */ #define LOGICRANGE 256 /*************************************************************************** END OF USER SETABLE DEFINES ***************************************************************************/ /* the limit of the math library */ #define MATHPRECISION 100 #if defined(_FLOATNUMTEST) # undef MAXDIGITS # undef MATHPRECISION # undef DECPRECISION # undef LOGICRANGE # define MAXDIGITS 130 # define MATHPRECISION 130 # define LOGICRANGE 96 #endif #define MAXBITS_IN_EXP (sizeof(int)*8-2) #define MAXEXP ((1 << MAXBITS_IN_EXP) - 1) #ifndef BITS_IN_EXP /* we need 2 extra bits during conversion, so that the exponent does not overflow while computing a base 2 expression */ # define BITS_IN_EXP MAXBITS_IN_EXP #endif /* necessary width of an integer to hold all possible exponents after a conversion to another base */ #define BITS_IN_HEXEXP BITS_IN_EXP #define BITS_IN_OCTEXP (BITS_IN_EXP + 1) #define BITS_IN_BINEXP (BITS_IN_EXP + 2) #ifndef MAXDIGITS # define MAXDIGITS 500 #endif /* MAXDIGITS */ #ifndef EXPMAX # define EXPMAX ((1 << (BITS_IN_EXP-1)) - 1) #endif /* EXPMAX */ #define EXPMIN (-EXPMAX - 1) #define EXPZERO ((int)((-1) << (sizeof(int)*8-1))) #define EXPNAN ((int)(~EXPZERO)) #ifndef DECPRECISION #define DECPRECISION MATHPRECISION #endif #define BINPRECISION ((33219*DECPRECISION)/10000 + 1) #define OCTPRECISION ((11073*DECPRECISION)/10000 + 1) #define HEXPRECISION ((8305*DECPRECISION)/10000 + 1) #ifndef LOGICRANGE # define LOGICRANGE (16*((BINPRECISION-2)/16)) #endif #endif /* _FLOATCONFIG_H */ deepin-calculator-1.0.2/math/floatconst.c000066400000000000000000000274251325241207700203730ustar00rootroot00000000000000/* floatconst.c: constants for higher math functions */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatconst.h" static char sExp[] = "2.7182818284""5904523536""0287471352""6624977572""4709369995" "9574966967""6277240766""3035354759""4571382178""5251664274" "2746639193""2003059921""8174135966""2904357290""0334295260" "5956307381""3232862794""3490763233""8298807531""9525101901" "1573834187"; static char sLn2[] = "0.6931471805""5994530941""7232121458""1765680755""0013436025" "5254120680""0094933936""2196969471""5605863326""9964186875" "4200148102""0570685734"; static char sLn3[] = "1.0986122886""6810969139""5245236922""5257046474""9055782274" "9451734694""3336374942""9321860896""6873615754""8137320887" "8797002906""5957865742"; static char sLn7[] = "1.9459101490""5531330510""5352743443""1797296370""8472958186" "1188459390""1499375798""6275206926""7787658498""5878715269" "9306169420""5851140912"; static char sLn10[] = "2.3025850929""9404568401""7991454684""3642076011""0148862877" "2976033327""9009675726""0967735248""0235997205""0895982983" "4196778404""2286248633"; static char sPhi[] = "1.6180339887""4989484820""4586834365""6381177203""0917980576" "2862135448""6227052604""6281890244""9707207204""1893911374" "8475408807""5386891752""1266338622""2353693179""3180060766" "7263544333""8908659593""9582905638""3226613199""2829026788" "0675208766"; static char sPi[] = "3.1415926535""8979323846""2643383279""5028841971""6939937510" "5820974944""5923078164""0628620899""8628034825""3421170679" "8214808651""3282306647""0938446095""5058223172""5359408128" "4811174502""8410270193""8521105559""6446229489""5493038196" "4428810976"; static char sPiDiv2[] = "1.5707963267""9489661923""1321691639""7514420985""8469968755" "2910487472""2961539082""0314310449""9314017412""6710585339" "9107404325""6641153324"; static char sPiDiv4[] = "0.7853981633""9744830961""5660845819""8757210492""9234984377" "6455243736""1480769541""0157155224""9657008706""3355292669" "9553702162""8320576662"; static char s2Pi[] = "6.2831853071""7958647692""5286766559""0057683943""3879875021" "1641949889""1846156328""1257241799""7256069650""6842341359" "6429617302""6564613294"; static char s1DivPi[] = "0.3183098861""8379067153""7767526745""0287240689""1929148091" "2897495334""6881177935""9526845307""0180227605""5325061719" "1214568545""3515916074"; static char sLnSqrt2PiMinusHalf[] = "0.4189385332""0467274178""0329736405""6176398613""9747363778" "3412817151""5404827656""9592726039""7694743298""6359541976" "2200564662""4634337446"; static char sSqrtPi[] = "1.7724538509""0551602729""8167483341""1451827975""4945612238" "7128213807""7898529112""8459103218""1374950656""7385446654" "1622682362""4282570666"; static char s1DivSqrtPi[] = "0.5641895835""4775628694""8079451560""7725858440""5062932899" "8856844085""7217106424""6844149341""4486743660""2021073634" "4302834790""6361707352"; static char s2DivSqrtPi[] = "1.1283791670""9551257389""6158903121""5451716881""0125865799" "7713688171""4434212849""3688298682""8973487320""4042147268" "8605669581""2723414703"; static char* sBernoulli[] = { "1", "6", "1", "-30", "1", "42", "1", "-30", "5", "66", "691", "-2730", "7", "6", "3617", "-510", "43867", "798", "174611", "-330", "854513", "138", "236364091", "-2730", "8553103", "6", "23749461029", "-870", "8615841276005", "14322", "7709321041217", "-510", "2577687858367", "6", "26315271553053477373", "-1919190", "2929993913841559", "6", "261082718496449122051", "-13530", "1520097643918070802691", "1806", "27833269579301024235023", "-690", "596451111593912163277961", "282", "5609403368997817686249127547", "-46410", "495057205241079648212477525", "66", "801165718135489957347924991853", "-1590", "29149963634884862421418123812691", "798", "2479392929313226753685415739663229", "-870", "84483613348880041862046775994036021", "354", "1215233140483755572040304994079820246041491", "-56786730", "12300585434086858541953039857403386151", "6", "106783830147866529886385444979142647942017", "-510", "1472600022126335654051619428551932342241899101", "64722", "78773130858718728141909149208474606244347001", "-30", "1505381347333367003803076567377857208511438160235", "4686", "5827954961669944110438277244641067365282488301844260429", "-140100870", "34152417289221168014330073731472635186688307783087", "6", "24655088825935372707687196040585199904365267828865801", "-30", "414846365575400828295179035549542073492199375372400483487", "3318", "4603784299479457646935574969019046849794257872751288919656867", "-230010", "1677014149185145836823154509786269900207736027570253414881613", "498", "2024576195935290360231131160111731009989917391198090877281083932477", "-3404310", "660714619417678653573847847426261496277830686653388931761996983", "6", "1311426488674017507995511424019311843345750275572028644296919890574047", "-61410", "1179057279021082799884123351249215083775254949669647116231545215727922535", "272118", "1295585948207537527989427828538576749659341483719435143023316326829946247", "-1410", "1220813806579744469607301679413201203958508415202696621436215105284649447", "6", "-4.70038339580357310785752555350060606545967373697590579151397635641e73", "1", "1.13180434454842492706751862577339342678903659547507479181789935417e76", "1", "-2.83822495706937069592641563364817647382846809280128821282285317145e78", "1", "7.40642489796788506297508271409209841768797317880887066731161003487e80", "1", "-2.00964548027566044834656196727153631868672708225328766243461301989e83", "1", "5.66571700508059414457193460305193569614194682875104206213875644522e85", "1", "-1.65845111541362169158237133743199123014949626147254647274024668156e88", "1", "5.03688599504923774192894219151801548124423742649032141415256513225e90", "1", "-1.58614682376581863693634015729664387827409784127789638804728645143e93", "1", "5.17567436175456269840732406825071225612408492359305508590621669403e95", "1", "-1.74889218402171173396900258776181591451414761618265448726273472159e98", "1", "6.11605199949521852558245252642641677807677268467832007168432401127e100", "1", "-2.2122776912707834942288323456712932445573185054987780150566552693e103", "1", "8.27227767987709698542210624599845957312046505184335662838488529886e105", "1", "-3.19589251114157095835916343691808148735262766710991122731845042431e108", "1", "1.27500822233877929823100243029266798669571917963897732951605857354e111", "1", "-5.25009230867741338994028246245651754469198940377552432607801345222e113", "1", "2.2301817894241625209869298198838728143738272150875878542490550781e116", "1", "-9.76845219309552044386335133989802393011669026749856789710001706619e118", "1", "4.40983619784529542722726228748131691918757542655281147353197591401e121", "1", "-2.05085708864640888397293377275830154864565966904008359530873982755e124", "1" }; floatstruct cBernoulliNum[68]; floatstruct cBernoulliDen[68]; floatstruct c1; floatstruct c2; floatstruct c3; floatstruct c12; floatstruct c16; floatstruct cExp; floatstruct cMinus1; floatstruct cMinus20; floatstruct c1Div2; floatstruct cLn2; floatstruct cLn3; floatstruct cLn7; floatstruct cLn10; floatstruct cPhi; floatstruct cPi; floatstruct cPiDiv2; floatstruct cPiDiv4; floatstruct c2Pi; floatstruct c1DivPi; floatstruct cSqrtPi; floatstruct cLnSqrt2PiMinusHalf; floatstruct c1DivSqrtPi; floatstruct c2DivSqrtPi; floatstruct cMinus0_4; floatstruct cUnsignedBound; int erfcdigits = 0; floatstruct erfccoeff[MAXERFCIDX]; floatstruct erfcalpha; floatstruct erfcalphasqr; floatstruct erfct2; floatstruct erfct3; void floatmath_init() { int i, save; floatnum_init(); save = float_setprecision(MAXDIGITS); float_create(&c1); float_setinteger(&c1, 1); float_create(&c2); float_setinteger(&c2, 2); float_create(&c3); float_setinteger(&c3, 3); float_create(&c12); float_setinteger(&c12, 12); float_create(&c16); float_setinteger(&c16, 16); float_create(&cMinus1); float_setinteger(&cMinus1, -1); float_create(&cMinus20); float_setinteger(&cMinus20, -20); float_create(&c1Div2); float_setscientific(&c1Div2, ".5", NULLTERMINATED); float_create(&cExp); float_setscientific(&cExp, sExp, NULLTERMINATED); float_create(&cLn2); float_setscientific(&cLn2, sLn2, NULLTERMINATED); float_create(&cLn3); float_setscientific(&cLn3, sLn3, NULLTERMINATED); float_create(&cLn7); float_setscientific(&cLn7, sLn7, NULLTERMINATED); float_create(&cLn10); float_setscientific(&cLn10, sLn10, NULLTERMINATED); float_create(&cPhi); float_setscientific(&cPhi, sPhi, NULLTERMINATED); float_create(&cPi); float_setscientific(&cPi, sPi, NULLTERMINATED); float_create(&cPiDiv2); float_setscientific(&cPiDiv2, sPiDiv2, NULLTERMINATED); float_create(&cPiDiv4); float_setscientific(&cPiDiv4, sPiDiv4, NULLTERMINATED); float_create(&c2Pi); float_setscientific(&c2Pi, s2Pi, NULLTERMINATED); float_create(&c1DivPi); float_setscientific(&c1DivPi, s1DivPi, NULLTERMINATED); float_create(&cSqrtPi); float_setscientific(&cSqrtPi, sSqrtPi, NULLTERMINATED); float_create(&cLnSqrt2PiMinusHalf); float_setscientific(&cLnSqrt2PiMinusHalf, sLnSqrt2PiMinusHalf, NULLTERMINATED); float_create(&c1DivSqrtPi); float_setscientific(&c1DivSqrtPi, s1DivSqrtPi, NULLTERMINATED); float_create(&c2DivSqrtPi); float_setscientific(&c2DivSqrtPi, s2DivSqrtPi, NULLTERMINATED); float_create(&cMinus0_4); float_setscientific(&cMinus0_4, "-.4", NULLTERMINATED); for (i = -1; ++i < MAXBERNOULLIIDX;) { float_create(&cBernoulliNum[i]); float_create(&cBernoulliDen[i]); float_setscientific(&cBernoulliNum[i], sBernoulli[2*i], NULLTERMINATED); float_setscientific(&cBernoulliDen[i], sBernoulli[2*i+1], NULLTERMINATED); } float_create(&cUnsignedBound); float_copy(&cUnsignedBound, &c1, EXACT); for (i = -1; ++i < 2*(int)sizeof(unsigned);) float_mul(&cUnsignedBound, &c16, &cUnsignedBound, EXACT); for (i = -1; ++i < MAXERFCIDX;) float_create(&erfccoeff[i]); float_create(&erfcalpha); float_create(&erfcalphasqr); float_create(&erfct2); float_create(&erfct3); float_setprecision(save); } void floatmath_exit() { int i; float_free(&c1); float_free(&c2); float_free(&c3); float_free(&c12); float_free(&c16); float_free(&cMinus1); float_free(&cMinus20); float_free(&c1Div2); float_free(&cExp); float_free(&cLn2); float_free(&cLn3); float_free(&cLn7); float_free(&cLn10); float_free(&cPhi); float_free(&cPi); float_free(&cPiDiv2); float_free(&cPiDiv4); float_free(&c2Pi); float_free(&c1DivPi); float_free(&cSqrtPi); float_free(&cLnSqrt2PiMinusHalf); float_free(&c1DivSqrtPi); float_free(&c2DivSqrtPi); float_free(&cMinus0_4); for (i = -1; ++i < MAXBERNOULLIIDX;) { float_free(&cBernoulliNum[i]); float_free(&cBernoulliDen[i]); } float_free(&cUnsignedBound); for (i = -1; ++i < MAXERFCIDX;) float_free(&erfccoeff[i]); float_free(&erfcalpha); float_free(&erfcalphasqr); float_free(&erfct2); float_free(&erfct3); } deepin-calculator-1.0.2/math/floatconst.h000066400000000000000000000043651325241207700203760ustar00rootroot00000000000000/* floatconst.h: constants for higher math functions */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATCONST_H #define FLOATCONST_H #include "floatnum.h" #define MAXBERNOULLIIDX 68 #define MAXERFCIDX 80 #ifdef __cplusplus extern "C" { #endif extern floatstruct c1; extern floatstruct c2; extern floatstruct c3; extern floatstruct c12; extern floatstruct cExp; extern floatstruct cMinus1; extern floatstruct cMinus20; extern floatstruct c1Div2; extern floatstruct cLn2; extern floatstruct cLn3; extern floatstruct cLn7; extern floatstruct cLn10; extern floatstruct cPhi; extern floatstruct cPi; extern floatstruct cPiDiv2; extern floatstruct cPiDiv4; extern floatstruct c2Pi; extern floatstruct c1DivPi; extern floatstruct cSqrtPi; extern floatstruct c1DivSqrtPi; extern floatstruct cLnSqrt2PiMinusHalf; extern floatstruct c2DivSqrtPi; extern floatstruct cMinus0_4; extern floatstruct cBernoulliNum[68]; extern floatstruct cBernoulliDen[68]; extern floatstruct cUnsignedBound; extern int erfcdigits; extern floatstruct erfccoeff[MAXERFCIDX]; extern floatstruct erfcalpha; extern floatstruct erfcalphasqr; extern floatstruct erfct2; extern floatstruct erfct3; void floatmath_init(); void floatmath_exit(); #ifdef __cplusplus } #endif #endif /* FLOATCONST_H */ deepin-calculator-1.0.2/math/floatconvert.c000066400000000000000000000363611325241207700207240ustar00rootroot00000000000000/* floatconvert.c: radix conversion, based on floatnum. */ /* Copyright (C) 2007 - 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatconvert.h" #include "floatcommon.h" #include "floatconst.h" #include "floatipower.h" #include typedef struct{ t_number_desc n; t_longint l; floatnum f; int bitlength; int trailing0; int lgbase; }t_ext_number; typedef t_ext_number* p_ext_number; /************************ conversion to/from longint *******************/ static unsigned _digitblock( floatnum f, int ofs, int count) { unsigned result; result = 0; for (; --count >= 0;) result = 10 * result + float_getdigit(f, ofs++); return result; } Error _floatnum2longint( t_longint* longint, floatnum f) { int digits; int i; unsigned factor; longint->length = 0; digits = float_getexponent(f) + 1; i = digits % 9; _longintadd(longint, _digitblock(f, 0, i)); factor = 1000000000; while (i < digits) { if (_longintmul(longint, factor) || _longintadd(longint, _digitblock(f, i, 9))) return IOConversionOverflow; i += 9; } /* extra element for floatlong operations */ *(longint->value+longint->length) = 0; return Success; } static void _setunsigned( floatnum f, unsigned value) { float_setinteger(f, value); if ((int)value < 0) float_add(f, f, &cUnsignedBound, EXACT); } void _longint2floatnum( floatnum f, t_longint* longint) { floatstruct tmp; int idx; float_setzero(f); if(longint->length == 0) return; float_create(&tmp); idx = longint->length - 1; for (; idx >= 0; --idx) { _setunsigned(&tmp, longint->value[idx]); float_mul(f, f, &cUnsignedBound, EXACT); float_add(f, f, &tmp, EXACT); } float_free(&tmp); } /************************** io routines **************************/ static int _max( int a, int b) { return a > b? a : b; } static char _validmode( char mode) { return mode >= IO_MODE_SCIENTIFIC && mode <= IO_MODE_COMPLEMENT; } static int lgbase( signed char base) { switch(base) { case 2: return 1; case 8: return 3; case 16: return 4; } return 0; } static char _getfnintdigit( int ofs, p_seq_desc n) { if (ofs <= n->digits) return float_getdigit((floatnum)(n->param), ofs); return 0; } static char _getfnfracdigit( int ofs, p_seq_desc n) { floatnum x; int exp; x = (floatnum)(n->param); exp = float_getexponent(x); if (ofs >= 0) return float_getdigit(x, ofs + exp + 1); return 0; } static void _setfndesc( p_number_desc n, floatnum x) { int digits; n->intpart.seq.base = 10; digits = _max(float_getexponent(x) + 1, 0); n->intpart.seq.digits = digits; n->intpart.seq.trailing0 = _max(digits - float_getlength(x), 0); n->intpart.seq.param = x; n->intpart.getdigit = _getfnintdigit; n->fracpart.seq.base = 10; n->fracpart.seq.leadingSignDigits = _max(-float_getexponent(x) - 1, 0); n->fracpart.seq.digits = float_getlength(x) - digits + n->fracpart.seq.leadingSignDigits; n->fracpart.seq.param = x; n->fracpart.getdigit = _getfnfracdigit; } static Error _pack2longint( t_longint* l, p_ext_seq_desc n) { int bitofs; int ofs; int logbase; logbase = lgbase(n->seq.base); ofs = n->seq.leadingSignDigits; if (_significantdigits(&n->seq) == 0) /* can be true in complement case: 0xFF00 */ --ofs; bitofs = (n->seq.digits - ofs) * logbase; if (!_longintsetsize(l, bitofs)) return IOBufferOverflow; for (; bitofs > 0;) { bitofs -= logbase; _orsubstr(l->value, bitofs, n->getdigit(ofs++, &n->seq)); } return Success; } static char _getlongintdigit( int ofs, p_seq_desc n) { if (ofs < 0 || ofs >= n->digits) return 0; return _bitsubstr(((t_longint*)(n->param))->value, (n->digits - ofs - 1) * lgbase(n->base)) & (n->base - 1); } static char _getlongintofsdigit( int ofs, p_seq_desc n) { p_number_desc nmb; int digits; nmb = (p_number_desc)(n->param); digits = n->digits; if (ofs < 0 || ofs >= digits) return 0; digits += nmb->fracpart.seq.digits; return _bitsubstr(((t_longint*)(nmb->fracpart.seq.param))->value, (digits - ofs - 1) * lgbase(n->base)) & (n->base - 1); } static void _setlongintdesc( p_ext_seq_desc n, t_longint* l, signed char base) { int lg; n->seq.base = base; lg = lgbase(base); n->seq.digits = (_bitlength(l) + lg - 1) / lg; n->seq.leadingSignDigits = 0; n->seq.trailing0 = _lastnonzerobit(l) / lg; n->seq.param = l; n->getdigit = _getlongintdigit; } static Error _packdec2int( floatnum x, p_ext_seq_desc n) { int ofs; int exp; int bufsz; int i; char buf[DECPRECISION]; float_setnan(x); ofs = n->seq.leadingSignDigits; exp = n->seq.trailing0; bufsz = n->seq.digits - ofs - exp; if (bufsz > DECPRECISION) return IOBufferOverflow; if (bufsz == 0) float_setzero(x); else for (i = -1; ++i < bufsz;) buf[i] = n->getdigit(ofs++, &n->seq) + '0'; float_setsignificand(x, NULL, buf, bufsz); float_setexponent(x, exp + bufsz - 1); return Success; } static Error _packbin2int( floatnum x, p_ext_seq_desc n) { t_longint l; Error result; float_setnan(x); if ((result = _pack2longint(&l, n)) != Success) return result; _longint2floatnum(x, &l); return Success; } static Error _pack2int( floatnum x, p_ext_seq_desc n) { switch(n->seq.base) { case IO_BASE_NAN: float_setnan(x); break; case IO_BASE_ZERO: float_setzero(x); break; case 10: return _packdec2int(x, n); default: return _packbin2int(x, n); } return Success; } static Error _pack2frac( floatnum x, p_ext_seq_desc n, int digits) { floatstruct tmp; int exp; Error result; n->seq.digits -= n->seq.trailing0; n->seq.trailing0 = 0; switch(n->seq.base) { case IO_BASE_NAN: float_setnan(x); break; case IO_BASE_ZERO: float_setzero(x); break; default: if ((result = _pack2int(x, n)) != Success) return result; float_create(&tmp); float_setinteger(&tmp, n->seq.base); _raiseposi(&tmp, &exp, n->seq.digits, digits+2); float_div(x, x, &tmp, digits + 2); float_setexponent(x, float_getexponent(x) - exp); float_free(&tmp); } n->seq.digits += n->seq.trailing0; return Success; } Error pack2floatnum( floatnum x, p_number_desc n) { floatstruct tmp; int digits; int saveerr; int saverange; Error result; signed char base; if ((result = _pack2int(x, &n->intpart)) != Success) return result; if (float_isnan(x)) return Success; saveerr = float_geterror(); saverange = float_setrange(MAXEXP); float_create(&tmp); float_move(&tmp, x); float_setzero(x); digits = DECPRECISION - float_getexponent(&tmp); if (digits <= 0 || (result = _pack2frac(x, &n->fracpart, digits)) == Success) float_add(x, x, &tmp, DECPRECISION); if (result != Success) return result; if ((!float_getlength(x)) == 0) /* no zero, no NaN? */ { base = n->prefix.base; float_setinteger(&tmp, base); if (n->exp >= 0) { _raiseposi_(&tmp, n->exp, DECPRECISION + 2); float_mul(x, x, &tmp, DECPRECISION + 2); } else { _raiseposi_(&tmp, -n->exp, DECPRECISION + 2); float_div(x, x, &tmp, DECPRECISION + 2); } } float_free(&tmp); float_setsign(x, n->prefix.sign == IO_SIGN_COMPLEMENT? -1 : n->prefix.sign); float_geterror(); float_seterror(saveerr); float_setrange(saverange); if (!float_isvalidexp(float_getexponent(x))) float_setnan(x); return float_isnan(x)? IOExpOverflow : Success; } static Error _outscidec( p_otokens tokens, floatnum x, p_number_desc n, int scale) { float_checkedround(x, scale + 1); n->exp = float_getexponent(x); float_setexponent(x, 0); _setfndesc(n, x); return desc2str(tokens, n, scale); } static int _checkbounds( floatnum x, int digits, signed char base) { if (float_getexponent(x) < 0) { float_muli(x, x, base, digits); return -1; } else if (float_asinteger(x) >= base) { float_divi(x, x, base, digits); return 1; } return 0; } static void _scale2int( floatnum x, int scale, signed char base) { floatstruct pwr; int pwrexp; (void)scale; if (scale != 0) { float_create(&pwr); float_setinteger(&pwr, base); _raiseposi(&pwr, &pwrexp, scale, DECPRECISION+4); float_mul(x, x, &pwr, DECPRECISION+4); float_addexp(x, pwrexp); float_free(&pwr); } float_roundtoint(x, TONEAREST); } static Error _fixp2longint( p_number_desc n, t_longint* l, floatnum x, int scale) { Error result; _scale2int(x, scale, n->prefix.base); result = _floatnum2longint(l, x); if (result != Success) return result; _setlongintdesc(&n->fracpart, l, n->prefix.base); return Success; } static int _extractexp( floatnum x, int scale, signed char base) { floatstruct pwr; floatstruct fbase; int decprec; int pwrexp; int exp; int logbase; (void)scale; logbase = lgbase(base); decprec = DECPRECISION + 3; exp = (int)(aprxlog10fn(x) * 3.321928095f); if (float_getexponent(x) < 0) exp -= 3; exp /= logbase; if (exp != 0) { float_create(&fbase); float_setinteger(&fbase, base); float_create(&pwr); float_copy(&pwr, &fbase, EXACT); _raiseposi(&pwr, &pwrexp, exp < 0? -exp : exp, decprec); if (float_getexponent(x) < 0) { float_addexp(x, pwrexp); float_mul(x, x, &pwr, decprec); } else { float_addexp(x, -pwrexp); float_div(x, x, &pwr, decprec); } float_free(&pwr); float_free(&fbase); } exp += _checkbounds(x, decprec, base); return exp; } static void _setscale( p_number_desc n, t_longint* l, int scale) { (void)l; n->intpart.seq.leadingSignDigits = 0; n->intpart.seq.trailing0 = n->fracpart.seq.trailing0 - scale; if (n->intpart.seq.trailing0 < 0) n->intpart.seq.trailing0 = 0; n->intpart.seq.base = n->fracpart.seq.base; n->intpart.seq.digits = n->fracpart.seq.digits - scale; n->intpart.getdigit = _getlongintofsdigit; n->intpart.seq.param = n; n->fracpart.seq.digits = scale; if (n->fracpart.seq.trailing0 >= scale) { n->fracpart.seq.base = IO_BASE_ZERO; n->fracpart.seq.trailing0 = scale; } } static Error _outscihex( p_otokens tokens, floatnum x, p_number_desc n, int scale) { t_longint l; Error result; n->exp = _extractexp(x, scale, n->prefix.base); result = _fixp2longint(n, &l, x, scale); if (result != Success) return result; /* rounding in _fixp2longint may have increased the exponent */ n->exp += n->fracpart.seq.digits - 1 - scale; _setscale(n, &l, n->fracpart.seq.digits - 1); return desc2str(tokens, n, scale); } static char _isvalidbase( signed char base) { return base == 10 || lgbase(base) != 0; } static Error _outsci( p_otokens tokens, floatnum x, p_number_desc n, int scale) { if (n->prefix.base == 10) return _outscidec(tokens, x, n, scale); return _outscihex(tokens, x, n, scale); } static Error _outfixpdec( p_otokens tokens, floatnum x, p_number_desc n, int scale) { int digits; digits = float_getexponent(x) + scale + 1; if (digits <= 0) /* underflow */ return IOConversionUnderflow; if (float_round(x, x, digits, TONEAREST) != TRUE) /* float_round() can err if the number contains too many digits */ return float_geterror(); _setfndesc(n, x); return desc2str(tokens, n, scale); } static Error _outfixphex( p_otokens tokens, floatnum x, p_number_desc n, int scale) { t_longint l; Error result; float_copy(x, x, DECPRECISION+1); result = _fixp2longint(n, &l, x, scale); if (result != Success) return result; if (l.length == 0) { result = float_geterror(); return result != Success ? result : IOConversionUnderflow; } _setscale(n, &l, scale); return desc2str(tokens, n, scale); } static Error _outfixp( p_otokens tokens, floatnum x, p_number_desc n, int scale) { if (n->prefix.base == 10) return _outfixpdec(tokens, x, n, scale); return _outfixphex(tokens, x, n, scale); } static Error _outengdec( p_otokens tokens, floatnum x, p_number_desc n, int scale) { int shift; float_checkedround(x, scale + 1); n->exp = float_getexponent(x); if (n->exp < 0) shift = 2 - (-n->exp-1) % 3; else shift = n->exp % 3; float_setexponent(x, shift); n->exp -= shift; _setfndesc(n, x); return desc2str(tokens, n, scale - shift); } static Error _outeng( p_otokens tokens, floatnum x, p_number_desc n, int scale) { if (n->prefix.base != 10 || scale < 2) return InvalidParam; return _outengdec(tokens, x, n, scale); } static Error _outcompl( p_otokens tokens, floatnum x, p_number_desc n, int scale) { (void)scale; if (!float_isinteger(x)) return IOInvalidComplement; if (n->prefix.sign == IO_SIGN_MINUS) n->prefix.sign = IO_SIGN_COMPLEMENT; else n->prefix.sign = IO_SIGN_NONE; return _outfixphex(tokens, x, n, 0); } static void _emptybuffer( p_buffer token) { if (token->sz > 0) *(token->buf) = '\0'; else token->buf = NULL; } static void _emptytokens( p_otokens tokens) { _emptybuffer(&tokens->intpart); _emptybuffer(&tokens->fracpart); tokens->sign = IO_SIGN_NONE; tokens->base = IO_BASE_NAN; tokens->exp = 0; } Error float_out( p_otokens tokens, floatnum x, int scale, signed char base, char outmode) { t_number_desc n; _emptytokens(tokens); /* do some sanity checks first */ if (!_validmode(outmode) || scale < 0 || !_isvalidbase(base)) return InvalidParam; _clearnumber(&n); if (float_iszero(x)) n.prefix.base = IO_BASE_ZERO; else if (!float_isnan(x)) n.prefix.base = base; if (!_isvalidbase(n.prefix.base)) /* NaN and 0 are handled here */ return desc2str(tokens, &n, 0); n.prefix.sign = float_getsign(x); float_abs(x); switch (outmode) { case IO_MODE_FIXPOINT: return _outfixp(tokens, x, &n, scale); case IO_MODE_ENG: return _outeng(tokens, x, &n, scale); case IO_MODE_COMPLEMENT: return _outcompl(tokens, x, &n, 0); default: return _outsci(tokens, x, &n, scale); } } Error float_in( floatnum x, p_itokens tokens) { t_number_desc n; Error result; if ((result = str2desc(&n, tokens)) == Success) result = pack2floatnum(x, &n); if (result != Success) { _seterror(x, BadLiteral); float_setnan(x); } return result; } deepin-calculator-1.0.2/math/floatconvert.h000066400000000000000000000054521325241207700207260ustar00rootroot00000000000000/* floatconvert.h: radix conversion, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATCONVERT_H # define FLOATCONVERT_H #include "floatnum.h" #include "floatlong.h" #ifdef __cplusplus extern "C" { #endif #define IO_MODE_SCIENTIFIC 0 #define IO_MODE_FIXPOINT 1 #define IO_MODE_ENG 2 #define IO_MODE_COMPLEMENT 3 /* converts the integer part of f to a binary coded bigint. Returns IOConversionOverflow, if the bigint overflows */ Error _floatnum2longint(t_longint* longint, floatnum f); /* converts a binary coded bigint into a floatnum */ void _longint2floatnum(floatnum f, t_longint* longint); /* the output process destroys x 'digits' are the number of digits after the dot. Regardless of the value of 'digits', a conversion is always done to DECPRECISION places Before reducing to 'digits' places the (converted) value is rounded. Trailing zeros are padded, if necessary, to fill to the right size. Errors: InvalidParam (if any of the parameters makes no sense like digits <= 0, or a not supported base) IOBufferOverflow (if the caller does not provide enough buffer in tokens) IOConversionOverflow (request requires too much buffer space for radix conversion) IOConversionUnderflow (request would produce leading zeros only) IOInvalidComplement (two's complement cannot be generated) */ Error float_out(p_otokens tokens, floatnum x, int digits, signed char base, char outmode); /* returns Success or one of the IO... codes Errors: BadLiteral, set in addition to the returned result */ Error float_in(floatnum x, p_itokens tokens); #ifdef __cplusplus } #endif #endif /* FLOATCONVERT_H */ deepin-calculator-1.0.2/math/floaterf.c000066400000000000000000000256711325241207700200220ustar00rootroot00000000000000/* floaterf.c: normal distribution integrals erf and the like */ /* Copyright (C) 2007 - 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floaterf.h" #include "floatconst.h" #include "floatcommon.h" #include "floatexp.h" #include "math.h" /* The Taylor expansion of sqrt(pi)*erf(x)/2 around x = 0. converges only for small |x| < 1 sufficiently. erf(x) = SUM[i>=0] (x^(2*i+1)/(i! * (2*i+1))) relative error for 100-digit evaluation: < 3e-100 */ char erfseries(floatnum x, int digits) { floatstruct xsqr, smd, pwr; int i, workprec, expx; expx = float_getexponent(x); workprec = digits + 2*expx + 2; if (workprec <= 0 || float_iszero(x)) /* for tiny arguments approx. == x */ return 1; float_create(&xsqr); float_create(&smd); float_create(&pwr); float_mul(&xsqr, x, x, workprec + 1); workprec = digits + float_getexponent(&xsqr) + 1; float_copy(&pwr, x, workprec + 1); i = 1; while (workprec > 0) { float_mul(&pwr, &pwr, &xsqr, workprec + 1); float_divi(&pwr, &pwr, -i, workprec + 1); float_divi(&smd, &pwr, 2 * i++ + 1, workprec); float_add(x, x, &smd, digits + 3); workprec = digits + float_getexponent(&smd) + expx + 2; } float_free(&pwr); float_free(&smd); float_free(&xsqr); return 1; } /* the asymptotic expansion of erfc, the bigger x is, the better. returns sum( (2*i+1)! /i! / x^(2*i) Relative error for x >= 16 and 100-digit evaluation is less than 9e-100 */ char erfcasymptotic(floatnum x, int digits) { floatstruct smd, fct; int i, workprec, newprec; float_create(&smd); float_create(&fct); workprec = digits - 2 * float_getexponent(x) + 1; if (workprec <= 0) { float_copy(x, &c1, EXACT); return 1; } float_mul(&fct, x, x, digits + 1); float_div(&fct, &c1Div2, &fct, digits); float_neg(&fct); float_copy(&smd, &c1, EXACT); float_setzero(x); newprec = digits; workprec = newprec; i = 1; while (newprec > 0 && newprec <= workprec) { workprec = newprec; float_add(x, x, &smd, digits + 4); float_muli(&smd, &smd, i, workprec + 1); float_mul(&smd, &smd, &fct, workprec + 2); newprec = digits + float_getexponent(&smd) + 1; i += 2; } float_free(&fct); float_free(&smd); return newprec <= workprec; } /* this algorithm is based on a paper from Crandall, who in turn attributes to Chiarella and Reichel. Found this in a paper from Borwein, Bailey and Girgensohn, and added minor improvements such as the adaptive working precision. There is a restriction with this algorithm not mentioned in the paper: x must not be too large, because the correcting term 2/(1-exp(2*pi*x/alpha)) becomes dominant and renders the result incorrect for large x. Fortunately, the valid range seems to overlap with the range of the asymptotic formula. Picks a fixed alpha suitable for the desired precision and evaluates the sum f(t, alpha) = Sum[k>0](exp(-k*k*alpha*alpha)/(k*k*alpha*alpha + t) f(t, alpha) is used in the evaluation of erfc(sqrt(t)) alpha is dependent on the desired precision; For a precision of p places, alpha should be < pi/sqrt(p*ln 10). Unfortunately, the smaller alpha is, the worse is the convergence rate, so alpha is usually approximately its upper limit. relative error for 100-digit evaluation < 5e-100 */ char erfcsum(floatnum x, /* should be the square of the parameter to erfc */ int digits) { int i; int workprec = 0; floatstruct sum, smd; floatnum Ei; if (digits > erfcdigits) { /* cannot re-use last evaluation's intermediate results */ for (i = MAXERFCIDX; --i >= 0;) /* clear all exp(-k*k*alpha*alpha) to indicate their absence */ float_free(&erfccoeff[i]); /* current precision */ erfcdigits = digits; /* create new alpha appropriate for the desired precision This alpha need not be high precision, any alpha near the one evaluated here would do */ float_setfloat(&erfcalpha, M_PI / aprxsqrt((digits + 4) * M_LN10)); float_round(&erfcalpha, &erfcalpha, 3, TONEAREST); float_mul(&erfcalphasqr, &erfcalpha, &erfcalpha, EXACT); /* the exp(-k*k*alpha*alpha) are later evaluated iteratively. Initiate the iteration here */ float_copy(&erfct2, &erfcalphasqr, EXACT); float_neg(&erfct2); _exp(&erfct2, digits + 3); /* exp(-alpha*alpha) */ float_copy(erfccoeff, &erfct2, EXACT); /* start value */ float_mul(&erfct3, &erfct2, &erfct2, digits + 3); /* exp(-2*alpha*alpha) */ } float_create(&sum); float_create(&smd); float_setzero(&sum); for (i = 0; ++i < MAXERFCIDX;) { Ei = &erfccoeff[i-1]; if (float_isnan(Ei)) { /* if exp(-i*i*alpha*alpha) is not available, evaluate it from the coefficient of the last summand */ float_mul(&erfct2, &erfct2, &erfct3, workprec + 3); float_mul(Ei, &erfct2, &erfccoeff[i-2], workprec + 3); } /* Ei finally decays rapidly. save some time by adjusting the working precision */ workprec = digits + float_getexponent(Ei) + 1; if (workprec <= 0) break; /* evaluate the summand exp(-i*i*alpha*alpha)/(i*i*alpha*alpha+x) */ float_muli(&smd, &erfcalphasqr, i*i, workprec); float_add(&smd, x, &smd, workprec + 2); float_div(&smd, Ei, &smd, workprec + 1); /* add summand to the series */ float_add(&sum, &sum, &smd, digits + 3); } float_move(x, &sum); float_free(&smd); return 1; } /* checks the quality of the asymptotic series for erfc. If the ratio of two subsequent summands from the series (the convergence rate) should not fall below `ratio' for a desired result precision (represented by digits), the number of summands n must not be greater than n <= (`digits'*ln 10 + 0.5 * ln 2)/(1 - ln `ratio') and the parameter x has to fullfil x >= sqrt(n/`ratio') `ratio' must be a value < 1, If you pick a value close to 1, you finally have to add quite a lot of summands from the series (in low precision), that affect a few digits at the low end of the result only. On the other hand, choosing a good convergence rate pushes the validity range of the series towards larger x. Here, the convergence rate is chosen to be 0.5, meaning that the addition of a summand from the series at least halfs the magnitude of the tail of the series. The evaluation is carried out in low precision using interger arithmetic rather than floating point data. For a 100 digit result the lower boundary of the range of the asymptotic series (truncated when the convergence rate falls below 0.5) is x > approx. 16.5. The above formulas estimate the limit x slightly too small, especially when `digits' is small. So, to compensate for that, r should be at least <= 0.92 */ static char _asymptotic_good( floatnum x, int digits) { /* all constants scaled by 10000 */ /* 1/ratio */ #define RATIO 20000 /* (1 - ln ratio) */ #define C_RATIO 16931 /* ln 10 */ #define LN10 23026 /* 0.5*ln 2 */ #define LN2DIV2 3466 int n, ix; if (!float_isvalidexp(float_getexponent(x) + 2) || (digits == 1 && float_cmp(x, &c2) >= 0)) return 1; /* 10000 * n/ratio */ n = RATIO*((digits * LN10 + LN2DIV2) / C_RATIO); float_addexp(x, 2); ix = float_asinteger(x); float_addexp(x, -2); return ix == 0 || ix >= 0x10000 || ix * ix >= n; } static int _logexpxsqr(int exp) { if (exp < 0) exp = 0; if (exp >= 0x1000) exp = 0x1000; return ((exp * exp * 73) >> 5); } char _erf( floatnum x, int digits) { int workprec; signed char sign; sign = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) > 0) { workprec = digits - _logexpxsqr(float_getexponent(x)); if (workprec < 0 || !_erfc(x, workprec)) float_setzero(x); float_sub(x, &c1, x, digits + 1); } else { erfnear0(x, digits); float_mul(x, x, &c2DivSqrtPi, digits + 2); } float_setsign(x, sign); return 1; } char _erfc( floatnum x, int digits) { floatstruct tmp, t2, t3; int expx, prec; char result; if (float_cmp(x, &c1Div2) <= 0) { /* use erfc(x) = 1 - erf(x) for small or negative x */ prec = digits; /* default for negative x, result is approx. 1 */ expx = float_getexponent(x); if (expx < 0) { /* |x| < 1, but not 0 */ prec = expx + digits + 2; if (prec <= 0) { float_copy(x, &c1, EXACT); return 1; } } _erf(x, prec); float_sub(x, &c1, x, digits + 1); return 1; } float_create(&tmp); if (_asymptotic_good(x, digits)) { if (float_mul(&tmp, x, x, digits + 5) && _exp(&tmp, digits + 3) && float_mul(&tmp, &tmp, x, digits + 3) && float_div(&tmp, &c1DivSqrtPi, &tmp, digits + 3)) { if (!erfcbigx(x, digits)) result = _seterror(x, EvalUnstable); else result = float_mul(x, x, &tmp, digits + 4); } else result = _seterror(x, Underflow); } else { result = 1; float_create(&t2); float_create(&t3); float_mul(&t2, x, x, digits + 2); float_copy(&tmp, &t2, EXACT); erfcsum(&tmp, digits); float_add(&tmp, &tmp, &tmp, digits + 1); float_copy(&t3, &t2, EXACT); float_reciprocal(&t2, digits + 1); float_add(&tmp, &tmp, &t2, digits + 2); float_neg(&t3); _exp(&t3, digits + 2); float_mul(&t3, &t3, &tmp, digits + 2); float_mul(&tmp, &erfcalpha, x, digits + 2); float_mul(&t3, &tmp, &t3, digits + 3); float_mul(&t3, &c1DivPi, &t3, digits + 2); /* quick estimate to find the right working precision */ float_div(&tmp, x, &erfcalpha, 4); float_mul(&tmp, &tmp, &c2Pi, 4); float_div(&tmp, &tmp, &cLn10, 4); prec = digits - float_getexponent(&t3) - float_asinteger(&tmp) + 1; /* add correction term */ if (prec > 0) { float_div(&tmp, x, &erfcalpha, prec + 3); float_mul(&tmp, &tmp, &c2Pi, prec + 4); _exp(&tmp, prec); float_sub(&tmp, &c1, &tmp, prec); float_div(&tmp, &c2, &tmp, prec); float_add(&t3, &t3, &tmp, digits + 1); } float_free(&t2); float_move(x, &t3); } float_free(&tmp); return result; } deepin-calculator-1.0.2/math/floaterf.h000066400000000000000000000026151325241207700200200ustar00rootroot00000000000000/* floaterf.h: normal distribution integrals erf and the like */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATERF_H #define FLOATERF_H #include "math/floatseries.h" #ifdef __cplusplus extern "C" { #endif #define erfnear0 erfseries #define erfcbigx erfcasymptotic char _erf(floatnum x, int digits); char _erfc(floatnum x, int digits); #ifdef __cplusplus } #endif #endif /* FLOATERF_H */ deepin-calculator-1.0.2/math/floatexp.c000066400000000000000000000212011325241207700200230ustar00rootroot00000000000000/* floatexp.c: exponential function and friends, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatconst.h" #include "floatcommon.h" #include "floatseries.h" #include "floatexp.h" /* uses the addition theorem cosh(2x)-1 == 2*(cosh x - 1)*(cosh x + 1) to reduce the argument to the range |x| < 0.01. Starting with x == 1, you need 7 reduction steps to achieve the desired magnitude. The relative error is < 8e-100 for a 100 digit result. The return value is 0, if the result underflows. |x| < 1, otherwise the final process, where the reductions are unwinded, becomes too unstable */ char _coshminus1lt1( floatnum x, int digits) { floatstruct tmp; int reductions; if (float_iszero(x)) return 1; float_abs(x); reductions = 0; while(float_getexponent(x) >= -2) { float_mul(x, x, &c1Div2, digits+1); ++reductions; } if (!coshminus1near0(x, digits) && reductions == 0) return !float_iszero(x); float_create(&tmp); for(; reductions-- > 0;) { float_mul(&tmp, x, x, digits); float_add(x, x, x, digits+2); float_add(x, x, &tmp, digits+2); float_add(x, x, x, digits+2); } float_free(&tmp); return 1; } /* sinh x == sqrt((cosh x - 1) * (cosh x + 1)) */ static void _sinhfromcoshminus1( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); float_add(&tmp, x, &c2, digits); float_mul(x, &tmp, x, digits+1); float_sqrt(x, digits+1); float_free(&tmp); } /* sinh x for |x| < 1. Derived from cosh x - 1. The relative error is < 8e-100 for a 100 digit result */ void _sinhlt1( floatnum x, int digits) { signed char sgn; if (float_getexponent(x) < -digits) /* for very small x: sinh(x) approx. == x. */ return; sgn = float_getsign(x); _coshminus1lt1(x, digits); _sinhfromcoshminus1(x, digits); float_setsign(x, sgn); } /* evaluates exp(x) - 1. This value can be obtained by exp(x) - 1 == sinh(x) + cosh(x) - 1 relative error < 8e-100 for a 100 digit result */ void _expminus1lt1( floatnum x, int digits) { floatstruct tmp; signed char sgn; if (float_getexponent(x) < -digits || float_iszero(x)) /* for very small x: exp(x)-1 approx.== x */ return; float_create(&tmp); sgn = float_getsign(x); _coshminus1lt1(x, digits); float_copy(&tmp, x, EXACT); _sinhfromcoshminus1(x, digits); float_setsign(x, sgn); float_add(x, x, &tmp, digits+1); float_free(&tmp); } /* exp(x) for 0 <= x < ln 10 relative error < 5e-100 */ void _expltln10( floatnum x, int digits) { int expx; int factor; char sgnf; expx = float_getexponent(x); factor = 1; if (expx >= -1) { sgnf = leadingdigits(x, 2 + expx); if (sgnf > 4) { if (sgnf < 9) { factor = 2; float_sub(x, x, &cLn2, digits+1); } else if (sgnf < 14) { factor = 3; float_sub(x, x, &cLn3, digits+1); } else if (sgnf < 21) { factor = 7; float_sub(x, x, &cLn7, digits+1); } else { factor = 10; float_sub(x, x, &cLn10, digits+1); } } } _expminus1lt1(x, digits); float_add(x, x, &c1, digits+1); if (factor != 1) float_muli(x, x, factor, digits+1); } /* exp(x) for all x. Underflow or overflow is indicated by the return value (0, if error) relative error for 100 digit results is 5e-100 */ char _exp( floatnum x, int digits) { floatstruct exp, tmp; int expx, extra; char ok; if (float_iszero(x)) { float_copy(x, &c1, EXACT); return 1; } expx = float_getexponent(x); if (expx >= (int)(BITS_IN_EXP >> 1)) /* obvious overflow or underflow */ return 0; float_create(&exp); float_create(&tmp); float_setzero(&exp); if (expx >= 0) { float_div(&exp, x, &cLn10, expx+1); float_int(&exp); extra = float_getexponent(&exp)+1; float_mul(&tmp, &exp, &cLn10, digits+extra); float_sub(x, x, &tmp, digits+extra); if (float_cmp(x, &cLn10) >= 0) { float_add(&exp, &exp, &c1, EXACT); float_sub(x, x, &cLn10, digits); } } if (float_getsign(x) < 0) { float_sub(&exp, &exp, &c1, EXACT); float_add(x, x, &cLn10, digits); } /* when we get here 0 <= x < ln 10 */ _expltln10(x, digits); /* just in case rounding leads to a value >= 10 */ expx = float_getexponent(x); if (expx != 0) float_addi(&exp, &exp, expx, EXACT); ok = 1; if (!float_iszero(&exp)) { expx = float_asinteger(&exp); ok = expx != 0; float_setexponent(x, expx); } float_free(&exp); float_free(&tmp); return ok && !float_isnan(x); } static char _0_5exp( floatnum x, int digits) { float_sub(x, x, &cLn2, digits + (3*logexp(x)/10)+1); return _exp(x, digits); } /* exp(x)-1 for all x. Overflow is indicated by the return value (0, if error) relative error for 100 digit results is 8e-100 */ char _expminus1( floatnum x, int digits) { int expr; if (float_abscmp(x, &c1Div2) < 0) { _expminus1lt1(x, digits); return 1; } if (float_getsign(x) < 0) { expr = (2*float_getexponent(x)/5); if (expr >= digits) float_setinteger(x, -1); else { _exp(x, digits-expr); float_sub(x, x, &c1, digits); } return 1; } if (!_exp(x, digits)) return 0; float_sub(x, x, &c1, digits); return 1; } static void _addreciproc( floatnum x, int digits, signed char sgn) { floatstruct tmp; int expx; expx = float_getexponent(x); if (2*expx < digits) { float_create(&tmp); float_muli(&tmp, x, 4, digits-2*expx); float_reciprocal(&tmp, digits-2*expx); float_setsign(&tmp, sgn); float_add(x, x, &tmp, digits+1); float_free(&tmp); } } /* cosh(x)-1 for all x. Underflow or overflow is indicated by the return value (0, if error) relative error for 100 digit results is 6e-100 */ char _coshminus1( floatnum x, int digits) { if (float_getexponent(x) < 0 || float_iszero(x)) return _coshminus1lt1(x, digits); if(!_0_5exp(x, digits)) return 0; _addreciproc(x, digits, 1); float_sub(x, x, &c1, digits); return 1; } /* sinh(x) for all x. Overflow is indicated by the return value (0, if error) relative error for 100 digit results is < 8e-100 */ char _sinh( floatnum x, int digits) { if (float_getexponent(x) < 0 || float_iszero(x)) _sinhlt1(x, digits); else { if(!_0_5exp(x, digits)) return 0; _addreciproc(x, digits, -1); } return 1; } /* tanh(x) for |x| <= 0.5. relative error for 100 digit results is < 7e-100 */ void _tanhlt0_5( floatnum x, int digits) { floatstruct tmp; signed char sgn; float_create(&tmp); sgn = float_getsign(x); float_abs(x); float_add(x, x, x, digits+1); _expminus1lt1(x, digits); float_add(&tmp, x, &c2, digits); float_div(x, x, &tmp, digits); float_setsign(x, sgn); float_free(&tmp); } /* tanh(x)-1 for x > 0. relative error for 100 digit results is < 9e-100 */ char _tanhminus1gt0( floatnum x, int digits) { if (float_add(x, x, x, digits+1) && _0_5exp(x, digits)) { float_add(x, x, &c1Div2, digits+1); float_reciprocal(x, digits+1); float_setsign(x, -1); return 1; } return 0; } void _tanhgt0_5( floatnum x, int digits) { int expx; expx = float_getexponent(x); if (5*expx >= digits) float_copy(x, &c1, EXACT); else { _tanhminus1gt0(x, digits - 5*expx); float_add(x, x, &c1, digits); } } char _power10( floatnum x, int digits) { int exp; if (float_isinteger(x)) { exp = float_asinteger(x); if (exp == 0 && !float_iszero(x)) return 0; float_copy(x, &c1, EXACT); float_setexponent(x, exp); return !float_isnan(x); } return float_mul(x, x, &cLn10, digits+2) && _exp(x, digits); } deepin-calculator-1.0.2/math/floatexp.h000066400000000000000000000033711325241207700200400ustar00rootroot00000000000000/* floatexp.h: exponential function and friends, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATEXP_H # define FLOATEXP_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif char _coshminus1lt1(floatnum x, int digits); void _sinhlt1(floatnum x, int digits); void _expminus1lt1(floatnum x, int digits); void _expltln10(floatnum x, int digits); char _exp(floatnum x, int digits); char _expminus1(floatnum x, int digits); char _coshminus1(floatnum x, int digits); void _tanhlt0_5(floatnum x, int digits); char _tanhminus1gt0(floatnum x, int digits); char _sinh(floatnum x, int digits); void _tanhgt0_5(floatnum x, int digits); char _power10(floatnum exponent, int digits); #ifdef __cplusplus } #endif #endif /* FLOATEXP_H */ deepin-calculator-1.0.2/math/floatgamma.c000066400000000000000000000272671325241207700203330ustar00rootroot00000000000000/* floatgamma.c: Gamma function, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatgamma.h" #include "floatconst.h" #include "floatcommon.h" #include "floatlog.h" #include "floatexp.h" #include "floattrig.h" /* asymptotic series of the Binet function for x >= 77 and a 100 digit computation, the relative error is < 9e-100. the series converges, if x and digits comply to 100 >= digits >= 2 x >= sqrt((digits*ln 10 + 0.5*ln 2)/1.0033). As a special case, for digits == 1, convergence is guaranteed, if x >= 1.8. */ char binetasymptotic(floatnum x, int digits) { floatstruct recsqr; floatstruct sum; floatstruct smd; floatstruct pwr; int i, workprec; if (float_getexponent(x) >= digits) { /* if x is very big, ln(gamma(x)) is dominated by x*ln x and the Binet function does not contribute anything substantial to the final result */ float_setzero(x); return 1; } float_create(&recsqr); float_create(&sum); float_create(&smd); float_create(&pwr); float_copy(&pwr, &c1, EXACT); float_setzero(&sum); float_div(&smd, &c1, &c12, digits+1); workprec = digits - 2*float_getexponent(x)+3; i = 1; if (workprec > 0) { float_mul(&recsqr, x, x, workprec); float_reciprocal(&recsqr, workprec); while (float_getexponent(&smd) > -digits-1 && ++i <= MAXBERNOULLIIDX) { workprec = digits + float_getexponent(&smd) + 3; float_add(&sum, &sum, &smd, digits+1); float_mul(&pwr, &recsqr, &pwr, workprec); float_muli(&smd, &cBernoulliDen[i-1], 2*i*(2*i-1), workprec); float_div(&smd, &pwr, &smd, workprec); float_mul(&smd, &smd, &cBernoulliNum[i-1], workprec); } } else /* sum reduces to the first summand*/ float_move(&sum, &smd); if (i > MAXBERNOULLIIDX) /* x was not big enough for the asymptotic series to converge sufficiently */ float_setnan(x); else float_div(x, &sum, x, digits); float_free(&pwr); float_free(&smd); float_free(&sum); float_free(&recsqr); return i <= MAXBERNOULLIIDX; } /* returns the number of summands needed in the asymptotic series to guarantee precision. Each extra summand yields roughly extra 1.8 digits. This is derived under the assumption, that the costs of an extra factor in the rising pochhammer symbol are about the same than those of an extra summand in the series */ static int _findorder( int digits) { return (5*digits + 5)/9; } /* returns how big x has to be to let the asymptotic series converge to at least precision. Derived from an estimation of the Bernouilli number inserted in the formula of a summand. */ static int _minx( int digits) { return (4657*_findorder(digits)-2750)/5000; } /* returns how much x has to be increased to let the asymptotic series converge to places */ static int _ofs( floatnum x, int digits) { int result; if (float_getexponent(x) >= 8) return 0; result = _minx(digits) - float_asinteger(x); return result <= 0? 0 : result; } /* evaluates the rising pochhammer symbol x*(x+1)*...*(x+n-1) (n >= 0) by multiplying. This can be expensive when n is large, so better restrict n to something sane like n <= 100. su stands for "small" and "unsigned" n */ static char _pochhammer_su( floatnum x, int n, int digits) { floatstruct factor; char result; /* the rising pochhammer symbol is computed recursively, observing that pochhammer(x, n) == pochhammer(x, p) * pochhammer(x+p, n-p). p is choosen as floor(n/2), so both factors are somehow "balanced". This pays off, if x has just a few digits, since only some late multiplications are full scale then and Karatsuba boosting yields best results, because both factors are always almost the same size. */ result = 1; switch (n) { case 0: float_copy(x, &c1, EXACT); case 1: break; default: float_create(&factor); float_addi(&factor, x, n >> 1, digits+2); result = _pochhammer_su(x, n >> 1, digits) && _pochhammer_su(&factor, n - (n >> 1), digits) && float_mul(x, x, &factor, digits+2); float_free(&factor); } return result; } /* evaluates ln(Gamma(x)) for all those x big enough to let the asymptotic series converge directly. Returns 0, if the result overflows relative error for a 100 gigit calculation < 5e-100 */ static char _lngammabigx( floatnum x, int digits) { floatstruct tmp1, tmp2; char result; result = 0; float_create(&tmp1); float_create(&tmp2); /* compute (ln x-1) * (x-0.5) - 0.5 + ln(sqrt(2*pi)) */ float_copy(&tmp2, x, digits+1); _ln(&tmp2, digits+1); float_sub(&tmp2, &tmp2, &c1, digits+2); float_sub(&tmp1, x, &c1Div2, digits+2); if (float_mul(&tmp1, &tmp1, &tmp2, digits+2)) { /* no overflow */ binetasymptotic(x, digits); float_add(x, &tmp1, x, digits+3); float_add(x, x, &cLnSqrt2PiMinusHalf, digits+3); result = 1; } float_free(&tmp2); float_free(&tmp1); return result; } static char _lngamma_prim_xgt0( floatnum x, floatnum revfactor, int digits) { int ofs; ofs = _ofs(x, digits); float_copy(revfactor, x, digits+1); _pochhammer_su(revfactor, ofs, digits); float_addi(x, x, ofs, digits+2); return _lngammabigx(x, digits); } static char _lngamma_prim( floatnum x, floatnum revfactor, int* infinity, int digits) { floatstruct tmp; char result; char odd; *infinity = 0; if (float_getsign(x) > 0) return _lngamma_prim_xgt0(x, revfactor, digits); float_copy(revfactor, x, digits + 2); float_sub(x, &c1, x, digits+2); float_create(&tmp); result = _lngamma_prim_xgt0(x, &tmp, digits); if (result) { float_neg(x); odd = float_isodd(revfactor); _sinpix(revfactor, digits); if (float_iszero(revfactor)) { *infinity = 1; float_setinteger(revfactor, odd? -1 : 1); } else float_mul(&tmp, &tmp, &cPi, digits+2); float_div(revfactor, revfactor, &tmp, digits+2); } float_free(&tmp); return result; } char _lngamma( floatnum x, int digits) { floatstruct factor; int infinity; char result; if (float_cmp(x, &c1) == 0 || float_cmp(x, &c2) == 0) return _setzero(x); float_create(&factor); result = _lngamma_prim(x, &factor, &infinity, digits) && infinity == 0; if (result) { float_abs(&factor); _ln(&factor, digits + 1); result = float_sub(x, x, &factor, digits+1); } float_free(&factor); if (infinity != 0) return _seterror(x, ZeroDivide); if (!result) float_setnan(x); return result; } char _gammagtminus20( floatnum x, int digits) { floatstruct factor; int ofs; char result; float_create(&factor); ofs = _ofs(x, digits+1); float_copy(&factor, x, digits+1); _pochhammer_su(&factor, ofs, digits); float_addi(x, x, ofs, digits+2); result = _lngammabigx(x, digits) && _exp(x, digits) && float_div(x, x, &factor, digits+1); float_free(&factor); if (!result) float_setnan(x); return result; } char _gamma( floatnum x, int digits) { floatstruct tmp; int infinity; char result; if (float_cmp(&cMinus20, x) > 0) { float_create(&tmp); result = _lngamma_prim(x, &tmp, &infinity, digits) && infinity == 0 && _exp(x, digits) && float_div(x, x, &tmp, digits + 1); float_free(&tmp); if (infinity != 0) return _seterror(x, ZeroDivide); if (!result) float_setnan(x); return result; } return _gammagtminus20(x, digits); } char _gammaint( floatnum integer, int digits) { int ofs; if (float_getexponent(integer) >=2) return _gammagtminus20(integer, digits); ofs = float_asinteger(integer); float_copy(integer, &c1, EXACT); return _pochhammer_su(integer, ofs-1, digits); } char _gamma0_5( floatnum x, int digits) { floatstruct tmp; int ofs; if (float_getexponent(x) >= 2) return _gamma(x, digits); float_create(&tmp); float_sub(&tmp, x, &c1Div2, EXACT); ofs = float_asinteger(&tmp); float_free(&tmp); if (ofs >= 0) { float_copy(x, &c1Div2, EXACT); if(!_pochhammer_su(x, ofs, digits)) return 0; return float_mul(x, x, &cSqrtPi, digits); } if(!_pochhammer_su(x, -ofs, digits)) return 0; return float_div(x, &cSqrtPi, x, digits); } static char _pochhammer_si( floatnum x, int n, int digits) { /* this extends the rising Pochhammer symbol to negative integer offsets following the formula pochhammer(x,n-1) = pochhammer(x,n)/(x-n+1) */ if (n >= 0) return _pochhammer_su(x, n, digits); return float_addi(x, x, n, digits) && _pochhammer_su(x, -n, digits) && float_reciprocal(x, digits); } static char _pochhammer_g( floatnum x, cfloatnum n, int digits) { /* this generalizes the rising Pochhammer symbol using the formula pochhammer(x,n) = Gamma(x+1)/Gamma(x-n+1) */ floatstruct tmp, factor1, factor2; int inf1, inf2; char result; float_create(&tmp); float_create(&factor1); float_create(&factor2); inf2 = 0; float_add(&tmp, x, n, digits+1); result = _lngamma_prim(x, &factor1, &inf1, digits) && _lngamma_prim(&tmp, &factor2, &inf2, digits) && (inf2 -= inf1) <= 0; if (inf2 > 0) float_seterror(ZeroDivide); if (result && inf2 < 0) float_setzero(x); if (result && inf2 == 0) result = float_div(&factor1, &factor1, &factor2, digits+1) && float_sub(x, &tmp, x, digits+1) && _exp(x, digits) && float_mul(x, x, &factor1, digits+1); float_free(&tmp); float_free(&factor2); float_free(&factor1); if (!result) float_setnan(x); return result; } static char _pochhammer_i( floatnum x, cfloatnum n, int digits) { /* do not use the expensive Gamma function when a few multiplications do the same */ /* pre: n is an integer */ int ni; signed char result; if (float_iszero(n)) return float_copy(x, &c1, EXACT); if (float_isinteger(x)) { result = -1; float_neg((floatnum)n); if (float_getsign(x) <= 0 && float_cmp(x, n) > 0) /* x and x+n have opposite signs, meaning 0 is among the factors */ result = _setzero(x); else if (float_getsign(x) > 0 && float_cmp(x, n) <= 0) /* x and x+n have opposite signs, meaning at one point you have to divide by 0 */ result = _seterror(x, ZeroDivide); float_neg((floatnum)n); if (result >= 0) return result; } if (float_getexponent(x) < EXPMAX/100) { ni = float_asinteger(n); if (ni != 0 && ni < 50 && ni > -50) return _pochhammer_si(x, ni, digits+2); } return _pochhammer_g(x, n, digits); } char _pochhammer( floatnum x, cfloatnum n, int digits) { if (float_isinteger(n)) return _pochhammer_i(x, n, digits); return _pochhammer_g(x, n, digits); } deepin-calculator-1.0.2/math/floatgamma.h000066400000000000000000000027301325241207700203240ustar00rootroot00000000000000/* floatgamma.h: Gamma function, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATGAMMA_H # define FLOATGAMMA_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif char _lngamma(floatnum x, int digits); char _gamma(floatnum x, int digits); char _gammaint(floatnum integer, int digits); char _gamma0_5(floatnum x, int digits); char _pochhammer(floatnum x, cfloatnum n, int digits); #ifdef __cplusplus } #endif #endif /* FLOATGAMMA_H */ deepin-calculator-1.0.2/math/floathmath.c000066400000000000000000000304641325241207700203430ustar00rootroot00000000000000/* floathmath.c: higher mathematical functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floathmath.h" #include "floatconst.h" #include "floatcommon.h" #include "floatlog.h" #include "floatexp.h" #include "floattrig.h" #include "floatpower.h" #include "floatipower.h" #include "floatgamma.h" #include "floaterf.h" #include "floatlogic.h" static char _cvtlogic( t_longint* lx, cfloatnum x) { if (float_isnan(x)) { float_seterror(NoOperand); return 0; } if (_floatnum2logic(lx, x)) return 1; float_seterror(OutOfLogicRange); return 0; } char float_lnxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) < 0 && float_getexponent(x) >= 0) return _seterror(x, OutOfDomain); _lnxplus1(x, digits); return 1; } char float_ln(floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) <= 0) return _seterror(x, OutOfDomain); _ln(x, digits); return 1; } char float_artanh( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getexponent(x) >= 0) return _seterror(x, OutOfDomain); _artanh(x, digits); return 1; } char float_artanhxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) >= 0 || float_abscmp(x, &c2) >= 0) return _seterror(x, OutOfDomain); if (float_cmp(x, &c1Div2) < 0) { float_neg(x); _artanh1minusx(x, digits); } else { float_sub(x, &c1, x, digits+1); _artanh(x, digits); } return 1; } char float_arsinh( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; _arsinh(x, digits); return 1; } char float_arcoshxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) < 0) return _seterror(x, OutOfDomain); _arcoshxplus1(x, digits); return 1; } char float_arcosh( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; float_sub(x, x, &c1, digits+1); return float_arcoshxplus1(x, digits); } char float_lg( floatnum x, int digits) { floatstruct tmp; int expx; if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) <= 0) return _seterror(x, OutOfDomain); float_create(&tmp); expx = float_getexponent(x); float_setexponent(x, 0); _ln(x, digits); float_div(x, x, &cLn10, digits); float_setinteger(&tmp, expx); float_add(x, x, &tmp, digits); float_free(&tmp); return 1; } char float_lb( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) <= 0) return _seterror(x, OutOfDomain); _ln(x, digits); float_div(x, x, &cLn2, digits); return 1; } char float_exp( floatnum x, int digits) { signed char sgn; if (!chckmathparam(x, digits)) return 0; sgn = float_getsign(x); if (_exp(x, digits)) return 1; if (sgn < 0) return _seterror(x, Underflow); return _seterror(x, Overflow); } char float_expminus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (_expminus1(x, digits)) return 1; return _seterror(x, Overflow); } char float_cosh( floatnum x, int digits) { int expx; if (!chckmathparam(x, digits)) return 0; expx = float_getexponent(x); if (2*expx+2 <= -digits || !_coshminus1(x, digits+2*expx)) { if (expx > 0) return _seterror(x, Overflow); float_setzero(x); } return float_add(x, x, &c1, digits); } char float_coshminus1( floatnum x, int digits) { int expx; if (!chckmathparam(x, digits)) return 0; expx = float_getexponent(x); if (_coshminus1(x, digits)) return 1; if (expx < 0) return _seterror(x, Underflow); return _seterror(x, Overflow); } char float_sinh( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (_sinh(x, digits)) return 1; return _seterror(x, Overflow); } char float_tanh( floatnum x, int digits) { signed char sgn; if (!chckmathparam(x, digits)) return 0; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) >= 0) _tanhgt0_5(x, digits); else _tanhlt0_5(x, digits); float_setsign(x, sgn); return 1; } char float_tanhminus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_cmp(x, &c1Div2) >= 0) return _tanhminus1gt0(x, digits)? 1 : _seterror(x, Underflow); if (!float_iszero(x)) { if (float_abscmp(x, &c1Div2) <= 0) _tanhlt0_5(x, digits); else { float_setsign(x, 1); _tanhgt0_5(x, digits); float_setsign(x, -1); } } return float_sub(x, x, &c1, digits); } char float_arctan( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; _arctan(x, digits); return 1; } char float_arcsin( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_abscmp(x, &c1) > 0) return _seterror(x, OutOfDomain); _arcsin(x, digits); return 1; } char float_arccos( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_abscmp(x, &c1) > 0) return _seterror(x, OutOfDomain); _arccos(x, digits); return 1; } char float_arccosxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) > 0 || float_abscmp(x, &c2) > 0) return _seterror(x, OutOfDomain); _arccosxplus1(x, digits); return 1; } char float_cos( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getexponent(x) >= DECPRECISION - 1 || !_trigreduce(x, digits)) return _seterror(x, EvalUnstable); _cos(x, digits); return 1; } char float_cosminus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (!_trigreduce(x, digits)) return _seterror(x, EvalUnstable); return _cosminus1(x, digits)? 1 : _seterror(x, Underflow); } char float_sin( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getexponent(x) >= DECPRECISION - 1 || !_trigreduce(x, digits)) return _seterror(x, EvalUnstable); _sin(x, digits); return 1; } char float_tan( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; return float_getexponent(x) >= DECPRECISION - 1 || !_trigreduce(x, digits) || !_tan(x, digits)? _seterror(x, EvalUnstable) : 1; } char float_raisei( floatnum power, cfloatnum base, int exponent, int digits) { if (digits <= 0 || digits > maxdigits) return _seterror(power, InvalidPrecision); if (float_isnan(base)) return _seterror(power, NoOperand); if (float_iszero(base)) { if (exponent == 0) return _seterror(power, OutOfDomain); if (exponent < 0) return _seterror(power, ZeroDivide); return _setzero(power); } digits += 14; if (digits > maxdigits) digits = maxdigits; float_copy(power, base, digits); if (!_raisei(power, exponent, digits) || !float_isvalidexp(float_getexponent(power))) { if (float_getexponent(base) < 0) return _seterror(power, Underflow); return _seterror(power, Overflow); } return 1; } char float_raise( floatnum power, cfloatnum base, cfloatnum exponent, int digits) { signed char sgn; if (float_isnan(exponent) || float_isnan(base)) return _seterror(power, NoOperand); if (digits <= 0 || digits > MATHPRECISION) return _seterror(power, InvalidPrecision); if (float_iszero(base)) { switch(float_getsign(exponent)) { case 0: return _seterror(power, OutOfDomain); case -1: return _seterror(power, ZeroDivide); } return _setzero(power); } sgn = float_getsign(base); if (sgn < 0) { if (!float_isinteger(exponent)) return _seterror(power, OutOfDomain); if ((float_getdigit(exponent, float_getexponent(exponent)) & 1) == 0) sgn = 1; } float_copy(power, base, digits+1); float_abs(power); if (!_raise(power, exponent, digits)) { float_seterror(Overflow); if (float_getexponent(base) * float_getsign(exponent) < 0) float_seterror(Underflow); return _setnan(power); } float_setsign(power, sgn); return 1; } char float_power10( floatnum x, int digits) { signed char sign; if (!chckmathparam(x, digits)) return 0; sign = float_getsign(x); if (_power10(x, digits)) return 1; return sign > 0? _seterror(x, Overflow) : _seterror(x, Underflow); } char float_gamma( floatnum x, int digits) { signed char sign; char result; if (!chckmathparam(x, digits)) return 0; sign = float_getsign(x); if (float_isinteger(x)) { if (sign <= 0) return _seterror(x, ZeroDivide); result = _gammaint(x, digits); } else if (float_getlength(x) - float_getexponent(x) == 2 && float_getdigit(x, float_getlength(x) - 1) == 5) result = _gamma0_5(x, digits); else result = _gamma(x, digits); if (!result) { if (sign < 0) float_seterror(Underflow); else float_seterror(Overflow); float_setnan(x); } return result; } char float_lngamma( floatnum x, int digits) { if (!x) return _seterror(x, OutOfDomain); return chckmathparam(x, digits) && _lngamma(x, digits)? 1 : _setnan(x); } char float_factorial( floatnum x, int digits) { if (!float_isnan(x)) float_add(x, x, &c1, digits); return float_gamma(x, digits); } char float_pochhammer( floatnum x, cfloatnum delta, int digits) { if (!chckmathparam(x, digits)) return 0; return float_isnan(delta)? _seterror(x, NoOperand) : _pochhammer(x, delta, digits); } char float_erf(floatnum x, int digits) { return chckmathparam(x, digits)? _erf(x, digits) : 0; } char float_erfc(floatnum x, int digits) { return chckmathparam(x, digits)? _erfc(x, digits) : 0; } char float_not( floatnum x) { t_longint lx; if(!_cvtlogic(&lx, x)) return _setnan(x); _not(&lx); _logic2floatnum(x, &lx); return 1; } char float_and( floatnum dest, cfloatnum x, cfloatnum y) { t_longint lx, ly; if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y)) return _setnan(dest); _and(&lx, &ly); _logic2floatnum(dest, &lx); return 1; } char float_or( floatnum dest, cfloatnum x, cfloatnum y) { t_longint lx, ly; if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y)) return _setnan(dest); _or(&lx, &ly); _logic2floatnum(dest, &lx); return 1; } char float_xor( floatnum dest, cfloatnum x, cfloatnum y) { t_longint lx, ly; if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y)) return _setnan(dest); _xor(&lx, &ly); _logic2floatnum(dest, &lx); return 1; } char _doshift( floatnum dest, cfloatnum x, cfloatnum shift, char right) { int ishift; t_longint lx; if (float_isnan(shift)) return _seterror(dest, NoOperand); if (!float_isinteger(shift)) return _seterror(dest, OutOfDomain); if(!_cvtlogic(&lx, x)) return 0; if (float_iszero(shift)) { float_copy(dest, x, EXACT); return 1; } ishift = float_asinteger(shift); if (ishift == 0) ishift = (3*LOGICRANGE) * float_getsign(shift); if (!right) ishift = -ishift; if (ishift > 0) _shr(&lx, ishift); else _shl(&lx, -ishift); _logic2floatnum(dest, &lx); return 1; } char float_shr( floatnum dest, cfloatnum x, cfloatnum shift) { return _doshift(dest, x, shift, 1); } char float_shl( floatnum dest, cfloatnum x, cfloatnum shift) { return _doshift(dest, x, shift, 0); } deepin-calculator-1.0.2/math/floathmath.h000066400000000000000000000332421325241207700203450ustar00rootroot00000000000000/* floathmath.h: higher mathematical functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATHMATH_H #define FLOATHMATH_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif /* evaluates ln(1+x) for x > -1. This function is especially useful for small x, where its computation is more precise than that of float_ln. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_lnxplus1(floatnum x, int digits); /* evaluates ln x (the logarithm to base e) for x > 0. Near x == 0, this function yields better results than float_lnxplus1. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_ln(floatnum x, int digits); /* evaluates lg x (the logarithm to base 10) for x > 0. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_lg(floatnum x, int digits); /* evaluates lb x (the logarithm to base 2) for x > 0. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_lb(floatnum x, int digits); /* evaluates arsinh x, the inverse function of sinh. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_arsinh(floatnum x, int digits); /* evaluates arcosh x, the inverse function of cosh, for x >= 1. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_arcosh(floatnum x, int digits); /* evaluates artanh x, the inverse function of tanh, for |x| < 1. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_artanh(floatnum x, int digits); /* evaluates artanh (1+x), for -2 < x <= 0. This function is especially useful, if you want to compute values near the pole at x == 1. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_artanhxplus1(floatnum x, int digits); /* evaluates arcosh (1+x), for x >= 0. This function is especially useful, if you want to compute values near the singularity of arcosh at x == 1. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) OutOfDomain */ char float_arcoshxplus1(floatnum x, int digits); /* evaluates exp(x) In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_exp(floatnum x, int digits); /* evaluates exp(x)-1. Use this in the neighbourhood of x == 0. In case of an error, x is set to NaN and 0 is returned. Errors: Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_expminus1(floatnum x, int digits); /* evaluates cosh(x). In case of an error, x is set to NaN and 0 is returned. Errors: Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_cosh(floatnum x, int digits); /* evaluates cosh(x) - 1. Yields better results in the neighbourhood of x == 0 than float_cosh. In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_coshminus1(floatnum x, int digits); /* evaluates sinh(x). In case of an error, x is set to NaN and 0 is returned. Errors: Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_sinh(floatnum x, int digits); /* evaluates tanh(x). In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_tanh(floatnum x, int digits); /* evaluates tanh(x)-1. Yields better results for large x > 0, when tanh x approx.== 1, than float_tanh. In case of an error, x is set to NaN and 0 is returned. Errors: Underflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_tanhminus1(floatnum x, int digits); /* evaluates 10^x. No optimization is applied for integer exponents. In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_power10(floatnum x, int digits); /* evaluates arctan x, yielding a result -pi/2 < result < pi/2. In case of an error, x is set to NaN and 0 is returned. Errors: NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_arctan(floatnum x, int digits); /* evaluates arcsin x for -1 <= x <= 1, yielding a result -pi/2 <= result <= pi/2. In case of an error, x is set to NaN and 0 is returned. Errors: OutOfDomain NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_arcsin(floatnum x, int digits); /* evaluates arccos x for -1 <= x <= 1, yielding a result 0 <= result <= pi. In case of an error, x is set to NaN and 0 is returned. Errors: OutOfDomain NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_arccos(floatnum x, int digits); /* evaluates arccos (1+x) for -2 <= x <= 0, yielding a result 0 <= result <= pi. This function is more precise in the neighbourhood of x == 0 than float_arccos. In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_arccosxplus1(floatnum x, int digits); /* evaluates tan x. For extreme large x, the periodicity of tan is not recognized any more, and a FLOAT_UNSTABLE error is reported. The same holds, if x is too near to a pole of tan, more precise, if |x-0.5*n*pi| < 1e- for some n. In case of an error, x is set to NaN and 0 is returned. Errors: EvalUnstable NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_tan(floatnum x, int digits); /* evaluates sin x. For extreme large x, the periodicity of sin is not recognized any more, and a FLOAT_UNSTABLE error is reported. In case of an error, x is set to NaN and 0 is returned. Errors: EvalUnstable NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_sin(floatnum x, int digits); /* evaluates cos x. For extreme large x, the periodicity of sin is not recognized any more, and a FLOAT_UNSTABLE error is reported. In case of an error, x is set to NaN and 0 is returned. Errors: EvalUnstable NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_cos(floatnum x, int digits); /* evaluates cos x - 1. In the neighbourhood of x==0, when cos x approx.== 1, this function yields better results than float_cos. For extreme large x, the periodicity of sin is not recognized any more, and a FLOAT_UNSTABLE error is reported. In case of an error, x is set to NaN and 0 is returned. Errors: Undeflow EvalUnstable NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_cosminus1(floatnum x, int digits); /* evaluates base^exponent In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow OutOfDomain (base <= 0 and most exponents) ZeroDivide ( base == 0 and exponent negative) NaNOperand InvalidPrecision (digits > maxprecision-14) */ char float_raisei(floatnum power, cfloatnum base, int exponent, int digits); /* evaluates base^exponent In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow OutOfDomain (base <= 0 and most exponents) ZeroDivide (base == 0 and exponent negative) NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_raise(floatnum power, cfloatnum base, cfloatnum exponent, int digits); /* evaluates Gamma(x) = (x-1)! In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow ZeroDivide (for integers <= 0) NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_gamma(floatnum x, int digits); /* evaluates ln(Gamma(x)) = ln((x-1)!) In case of an error, x is set to NaN and 0 is returned. Errors: Overflow OutOfDomain (for x <= 0) NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_lngamma(floatnum x, int digits); /* evaluates x! In case of an error, x is set to NaN and 0 is returned. Errors: Underflow Overflow ZeroDivide (for integers < 0) NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_factorial(floatnum x, int digits); /* evaluates gamma(x+delta)/gamma(x). If delta is a positive integer, this is the Pochhammer symbol x*(x+1)*...*(x+delta-1). The poles of the gamma function are handled appropriately. Errors: Underflow Overflow ZeroDivide (not annihilated pole in the nominator) NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_pochhammer(floatnum x, cfloatnum delta, int digits); /* evaluates erf(x). NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_erf(floatnum x, int digits); /* evaluates erfc(x). Underflow NaNOperand InvalidPrecision (digits > MATHPRECISION) */ char float_erfc(floatnum x, int digits); /* cuts off the fraction part of and complements the bits in the 2's complement representation of then. The corresponding integer of the result is stored back in . In case of an error, is set to NaN and 0 is returned. Errors: OutOfLogicRange NaNOperand */ char float_not(floatnum x); /* uses the integer parts of and and builds their 2's complement representation. The resulting strings are and-ed and the corresponding integer is stored in dest. In case of an error, is set to NaN and 0 is returned. Errors: OutOfLogicRange NaNOperand */ char float_and(floatnum dest, cfloatnum x, cfloatnum y); /* uses the integer parts of x and y and builds their 2's complement representation. The resulting strings are or-ed and the corresponding integer is stored in dest. In case of an error, is set to NaN and 0 is returned. Errors: OutOfLogicRange NaNOperand */ char float_or(floatnum dest, cfloatnum x, cfloatnum y); /* uses the integer parts of and and builds their 2's complement representation. The resulting strings are xor-ed and the corresponding integer is stored in dest. In case of an error, is set to NaN and 0 is returned. Errors: OutOfLogicRange NaNOperand */ char float_xor(floatnum dest, cfloatnum x, cfloatnum y); /* uses the integer part of and builds its 2's complement representation as LOGICRANGE bits. The resulting bitstring is then shifted y times to the left. Shifted out bits are dropped, to the right 0 bits are fed in. The corresponding integer of the resulting bitstring is stored in . has to be an integer or an error is reported. If it is negative, this operation turns into a shift right. In case of an error, is set to NaN and 0 is returned. Errors: OutOfDomain (y not an integer) OutOfLogicRange NaNOperand */ char float_shl(floatnum dest, cfloatnum x, cfloatnum y); /* uses the integer part of and builds its 2's complement representation as LOGICRANGE bits. The resulting bitstring is then shifted y times to the right. Shifted out bits are dropped, to the left the sign bit is duplicated. The corresponding integer of the resulting bitstring is stored in . has to be an integer or an error is reported. If it is negative, this operation turns into a shift left. In case of an error, is set to NaN and 0 is returned. Errors: OutOfDomain (y not an integer) OutOfLogicRange NaNOperand */ char float_shr(floatnum dest, cfloatnum x, cfloatnum y); #ifdef __cplusplus } #endif #endif /* FLOATLOG_H */ deepin-calculator-1.0.2/math/floatincgamma.c000066400000000000000000000155021325241207700210120ustar00rootroot00000000000000/* floatincgamma.h: incomplete gamma function */ /* Copyright (C) 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatincgamma.h" #include "floatconst.h" #include "floatcommon.h" #include "floathmath.h" /* many ideas are from a paper of Serge Winitzki, "Computing the incomplete Gamma function to arbitrary precision" */ /* The critical line of the lower incomplete gamma function lowgamma(a, z) is composed of all non-positive real 'a' along with z == 0. It cannot be continued on this line. Near this line lowgamma behaves approximately as 1. z^a/a, a not close to a negative integer 2. (z^a/a) + (-1)^k*z^h/h/k!, where -k is a negative integer very close to a and h = a + k very small If h << z the second summand in 2. becomes dominant, otherwise z^a/a is a rough estimate of lowgamma(a, z), diverging for fixed non-positive 'a* and z -> 0. Since z^a is true complex for real z < 0, lowgamma cannot be continued in the real number domain accross the critical line, except for 'a' a negative integer. reglowgammanearpole computes f(x, k, h) = x^(k-h) * [lowgamma(-k+h, x) - (-1)^k * x^h / h / k!] where k is an integer >= 0. It should only be used for |h| <= 0.5 and |x| not much bigger than 2. f is useful for computing both the lower and upper incomplete gamma function for values a, x close to the critical line. The term (-1)^k * x^h/(k!*h) subtracts the pole Gamma(-k), and, in addition, lowgamma(a, x) is regularized by the factor x^(k-h), in order to eliminate the singularity introduced by the factor z^a/a. f is real-valued even for negative x, where lowgamma is true complex. f is not continuous at a = (-2k-1)/2, k integer > 0, where the subtracted pole changes */ static void reglowgammanearpole(floatnum x, int k, cfloatnum h, int digits){ floatstruct tmp; float_create(&tmp); if (float_iszero(x) || float_getexponent(x) < -digits-3){ // tiny x, return the first element of the series: k > 0? 1/(h-k) : -x/(1+h) if (k > 0){ float_addi(x, h, -k, digits+2); float_reciprocal(x, digits+1); } else{ float_sub(&tmp, &cMinus1, h, digits+2); float_div(x, x, &tmp, digits+1); } } else{ // evaluate the series int workprec = digits+5; int i = 0; int expx = float_getexponent(x); floatstruct summand; floatstruct sum; float_create(&summand); float_create(&sum); float_copy(&tmp, &c1, EXACT); float_setzero(&sum); while (workprec > 0){ if (i != k){ float_addi(&summand, h, i-k, workprec); float_div(&summand, &tmp, &summand, workprec); float_add(&sum, &sum, &summand, digits+5); } workprec = digits - float_getexponent(&sum) + float_getexponent(&summand) + expx+5; if (workprec > 0){ float_mul(&tmp, &tmp, x, workprec); float_divi(&tmp, &tmp, -++i, workprec); } } float_move(x, &sum); // frees sum as a side-effect // float_free(&sum); float_free(&summand); } float_free(&tmp); } /* computes x^a (withExp = 0) or exp(-x)*x^a (withExp = 1) x^a[*exp(-x)] is the regulizing factor of the lower incomplete gamma function */ static char regulizingfactor(floatnum x, cfloatnum a, int digits, char withExp){ char result; floatstruct tmp; float_create(&tmp); result = float_raise(&tmp, x, a, digits); if (result && withExp){ float_neg(x); result = float_exp(x, digits) && float_mul(&tmp, &tmp, x, digits); } float_move(x, &tmp); // frees tmp as a side-effect // float_free(&tmp); return result; } /* adds (-1)^k * x^h / (h * k!) to lowgamma, accounting for the pole of the gamma function, h!= 0 */ static char addgammapole(floatnum lowgamma, cfloatnum x, int k, cfloatnum h, int digits){ // estimate the size of this summand, often it will not contribute // to the result char result = 1; float fh = float_getexponent(h) >= -37? float_asfloat(h) : 0; float xx; float fexp = aprxlog10fn(x); fexp *= fh; fexp -= aprxlog10fn(h); xx = aprxlngamma(k+1); xx *= 0.434294481903f; fexp += xx; fexp +=1; /* float fexp = (aprxlog2fn(x)*fh - aprxlog2fn(h)) * 0.301029995663981f - aprxlngamma(k+1) * 0.434294481903f + 1;*/ if (fexp > EXPMIN){ int exp = fexp; int explowgamma = float_getexponent(lowgamma); int workprec = digits + 3; if (exp < explowgamma-3) workprec = digits - explowgamma - exp -3; if (workprec > 0){ floatstruct pwr; floatstruct fct; float_create(&pwr); float_create(&fct); float_setinteger(&fct, k); result = float_raise(&pwr, x, h, workprec) && float_factorial(&fct, workprec) && float_div(&pwr, &pwr, &fct, workprec) && float_div(&pwr, &pwr, h, workprec); if ((k & 1) != 0) float_neg(&pwr); result = result && float_add(lowgamma, lowgamma, &pwr, digits+2); float_free(&fct); float_free(&pwr); } } return result; } /* for 0.5 > a and ln Gamma(-a) / ln 10 < 2 * digits */ static char lowgammanearpole(floatnum x, cfloatnum a, int digits){ int k = float_getexponent(a); char result; floatstruct h; floatstruct lowgamma; floatstruct factor; float_create(&h); float_create(&lowgamma); float_create(&factor); float_sub(&h, a, &c1Div2, k < -1? 2 : k+3); k = -float_asinteger(&h); float_addi(&h, a, k, digits+2); float_copy(&lowgamma, x, digits+2); float_copy(&factor, x, digits+3); reglowgammanearpole(&lowgamma, k, &h, digits); result = regulizingfactor(&factor, a, digits, 0) && float_mul(&lowgamma, &lowgamma, &factor, digits+2) && addgammapole(&lowgamma, x, k, &h, digits); float_move(x, &lowgamma); // frees lowgamma float_free(&lowgamma); float_free(&h); return result; } void testincgamma(floatnum x, cfloatnum a, int digits){ lowgammanearpole(x, a, digits); } deepin-calculator-1.0.2/math/floatincgamma.h000066400000000000000000000024641325241207700210220ustar00rootroot00000000000000/* floatincgamma.h: incomplete gamma function */ /* Copyright (C) 2009 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATINCGAMMA_H # define FLOATINCGAMMA_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif void testincgamma(floatnum x, cfloatnum a, int digits); #ifdef __cplusplus } #endif #endif /* FLOATINCGAMMA_H */ deepin-calculator-1.0.2/math/floatio.c000066400000000000000000000546041325241207700176530ustar00rootroot00000000000000/* floatio.c: low level conversion, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatio.h" #include "floatlong.h" #include typedef enum { NmbNormal, NmbSpecial, NmbBufferOverflow } NmbType; /* Besides the regular bases 2, 8, 10 and 16, there are three others (IO_BASE_DEFAULT, IO_BASE_NAN and IO_BASE_ZERO) used internally to mark special situations. They are called pseudo-bases, because you cannot use them as parameter to floatnum functions */ static char _isspecial( signed char base) { switch (base) { case IO_BASE_NAN: case IO_BASE_ZERO: case IO_BASE_DEFAULT: return 1; } return 0; } /*-------------- ASCII based functions -------------*/ static char emptystr = '\0'; /* sort of alias for (strlen == 0). I don't have access to a POSIX manual, so I don't know how strlen reacts on NULL.*/ static char _isempty( const char* p) { return p == NULL || *p == '\0'; } /* copies the null-terminated ASCIIZ string src into the buffer dest. If the buffer is too small to hold src, 0 is returned */ static char _setstr( p_buffer dest, const char* src) { if (dest->sz > 0) { if (src == NULL) *(dest->buf) = '\0'; else if (dest->sz < (int)strlen(src) + 1) return 0; else strcpy(dest->buf, src); } return 1; } /* looks, whether dest begins with the substring in pattern */ static int _match( const char* dest, const char* pattern) { int lg; if (_isempty(dest) || _isempty(pattern)) return 0; lg = strlen(pattern); return strncmp(dest, pattern, lg) == 0? lg : 0; } /* converts an ASCII encoded hexagesimal digit a corresponding value < 16 */ char _ascii2digit( char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return (c - 'A') + 10; if (c >= 'a' && c <= 'f') return (c - 'a') + 10; return NO_DIGIT; } static char hexdigits[] = "0123456789ABCDEF"; /* converts a value 0 <=x < 16 into a hexdigit */ char _digit2ascii( int value) { return hexdigits[value]; } /* advances the pointer buf until it points to the first character not being a valid digit of base base. The return pointer is the initial value of buf, or NULL if no digit was found */ static const char* _scandigits( const char** buf, char base) { const char* p; const char* result; result = *buf; p = result - 1; while (_ascii2digit(*++p) < base); *buf = p; return p == result? NULL : result; } /*-------------------- t_seq_desc ---------------*/ /* returns the offset6 of the last significant digit */ static int _ofslastnz( p_seq_desc n) { return n->digits - n->trailing0 - 1; } /* number of significant digits in a number sequence */ int _significantdigits( p_seq_desc n) { return n->digits - n->leadingSignDigits - n->trailing0; } /* number of digits without leading zeros in a sequence. If the sequence describes an integer, these are the digits of this integer */ static int _intdigits( p_seq_desc n) { return n->digits - n->leadingSignDigits; } /* has a sequence significant digits? */ static char _iszero( p_seq_desc n) { return _significantdigits(n) == 0; } /* returns a digit from an ASCIIZ string containing digits only */ static char _getseqdigit( int ofs, p_seq_desc n) { if (ofs < 0 || ofs > _ofslastnz(n)) return 0; return _ascii2digit(*((char*)(n->param) + ofs)); } /* returns a digit from an ASCIIZ string containing digits only, but complements them */ static char _getcmpldigit( int ofs, p_seq_desc n) { int lastnz; char c; lastnz = _ofslastnz(n); if (ofs > lastnz) return 0; c = n->base - _getseqdigit(ofs, n) - (ofs == lastnz? 0 : 1); return c == n->base? 1 : c; } /* initializes a structure used for copying digit sequences */ static void _clearint( p_ext_seq_desc n) { n->seq.leadingSignDigits = 0; n->seq.digits = 0; n->seq.trailing0 = 0; n->seq.base = IO_BASE_ZERO; n->seq.param = NULL; n->getdigit = _getseqdigit; } /*---------------------- t_[io]token ------------------*/ /* initializes a structure used for describing a floating point number */ void _clearnumber( p_number_desc n) { n->prefix.sign = IO_SIGN_NONE; n->prefix.base = IO_BASE_NAN; _clearint(&n->intpart); _clearint(&n->fracpart); n->exp = 0; } /* creates a sequence descriptor from an ASCII digit sequence, not necessarily terminated by \0. After maxdigits digits, all following digits are assumed to be zero, regardless of their true value. */ static void _str2seq( p_ext_seq_desc n, const char* digits, int maxdigits, signed char base, char complement) { /* pre: n has to be initialized to describe a zero */ const char* p; const char* pz; char leadingdigit; unsigned char c; leadingdigit = 0; if (complement) { leadingdigit = base - 1; n->getdigit = _getcmpldigit; } p = digits; /* skip sign digits (usually 0, in complement mode F, 7 or 1 */ for (; _ascii2digit(*p) == leadingdigit; ++p); n->seq.leadingSignDigits = p - digits; /* pz is pointer to first trailing zero */ pz = p; for (; (c = _ascii2digit(*(p++))) < base;) { if (--maxdigits >= 0 && c != 0) pz = p; } n->seq.trailing0 = p - pz - 1; n->seq.digits = p - digits - 1; n->seq.param = (void*)digits; if (complement || _significantdigits(&n->seq) != 0) n->seq.base = base; } /* copy count digits (leading zeros included) from the digit sequence described by n to an ASCII buffer */ static Error _seq2str( p_buffer dest, int count, p_ext_seq_desc n) { int ofs; char* buf; ofs = 0; if (count >= dest->sz) return IOBufferOverflow; buf = dest->buf; for (; ofs < count; ++ofs) *(buf++) = _digit2ascii(n->getdigit(ofs, &n->seq)); *(buf) = '\0'; return Success; } /* copy all digits (leading zeros included) from the digit sequence described by n to an ASCII buffer, but complement the sequence before writing to the buffer */ static Error _cmplseq2str( p_buffer dest, p_ext_seq_desc n) { int bound; int ofs; int lastnz; char* buf; char c; buf = dest->buf; bound = _intdigits(&n->seq); if (bound + 1 > dest->sz) return IOBufferOverflow; lastnz = _ofslastnz(&n->seq); for (ofs = -1; ++ofs < lastnz;) { c = n->seq.base - n->getdigit(ofs, &n->seq) - 1; *(buf++) = _digit2ascii(c); } c = n->getdigit(ofs, &n->seq); if (c != 1 || _significantdigits(&n->seq) != 1) *(buf++) = _digit2ascii(n->seq.base - c); else { --bound; --ofs; } for (; ++ofs < bound;) *(buf++) = _digit2ascii(0); *(buf) = '\0'; return Success; } /* create a descriptor from a sequence of digits, assuming the sequence is an integer */ static Error str2int( p_ext_seq_desc n, const char* value, p_prefix prefix, int maxdigits) { char complement; if (prefix->base == IO_BASE_NAN) return IONoBase; complement = prefix->sign == IO_SIGN_COMPLEMENT; if (complement) { n->getdigit = _getcmpldigit; /* necessary, because when value is empty, base = IO_BASE_ZERO */ n->seq.base = prefix->base; } if (value) _str2seq(n, value, maxdigits, prefix->base, complement); return Success; } /* if base describes a special value (0 or NaN), the normal conversion routines fail. This routine creates special output values for these bases, and return nmbBufferOverflow: if the buffer is too small nmbSpecial: if it created output nmbNormal: if base stands for a usual number that the normal routines should deal with */ static NmbType _special2str( p_otokens tokens, signed char base) { const char* p; switch (base) { case IO_BASE_ZERO: p = "0"; break; case IO_BASE_NAN: p = "NaN"; break; default: return NmbNormal; } return _setstr(&tokens->intpart, p)? NmbSpecial : NmbBufferOverflow; } /* create an ASCIIZ sequence of the integer part, set sign and base. */ static Error int2str( p_otokens tokens, p_number_desc n, char complement) { tokens->sign = n->prefix.sign; tokens->base = n->prefix.base; switch (_special2str(tokens, n->prefix.base)) { case NmbSpecial: return Success; case NmbBufferOverflow: return IOBufferOverflow; default: break; /* NmbNormal */ } /* no special encodings */ if (complement) return _cmplseq2str(&tokens->intpart, &n->intpart); return _seq2str(&tokens->intpart, _intdigits(&n->intpart.seq), &n->intpart); } /* do some sanity checks, create descriptors of integer and fraction part in tokens, set sign and base */ static Error str2fixp( p_number_desc n, p_itokens tokens) { Error result; int maxdigits; maxdigits = tokens->maxdigits; n->prefix.base = tokens->base; n->prefix.sign = tokens->sign; if (tokens->sign == IO_SIGN_COMPLEMENT && (!_isempty(tokens->fracpart) || tokens->exp)) return IOInvalidComplement; result = str2int(&n->intpart, tokens->intpart, &n->prefix, maxdigits); if (_isspecial(n->prefix.base)) return result; if (!_isempty(tokens->fracpart)) _str2seq(&n->fracpart, tokens->fracpart, maxdigits - _intdigits(&n->intpart.seq), n->prefix.base, 0); if (n->prefix.sign != IO_SIGN_COMPLEMENT && n->intpart.seq.digits + n->fracpart.seq.digits == 0) return IONoSignificand; if (n->prefix.sign != IO_SIGN_COMPLEMENT && _iszero(&n->intpart.seq) && _iszero(&n->fracpart.seq)) n->prefix.base = IO_BASE_ZERO; return Success; } /* convert integer and fraction part into ASCIIZ sequences */ static Error fixp2str( p_otokens tokens, p_number_desc n, int scale) { Error result; result = int2str(tokens, n, n->prefix.sign == IO_SIGN_COMPLEMENT); if (result != Success || _isspecial(n->prefix.base)) return result; return _seq2str(&tokens->fracpart, scale, &n->fracpart); } /* create a descriptor from the digit sequence of the exponent */ static Error _exp2desc( p_number_desc n, p_itokens tokens) { if (tokens->expsign != IO_SIGN_NONE || tokens->exp) { unsigned upperLimit; signed char sign; switch (tokens->base) { case 2 : upperLimit = BITS_IN_BINEXP - 1; break; case 8 : upperLimit = BITS_IN_OCTEXP - 1; break; case 16: upperLimit = BITS_IN_HEXEXP - 1; break; default: upperLimit = BITS_IN_EXP - 1; break; } upperLimit = (1 << (upperLimit)) - 1; sign = tokens->expsign; switch (sign) { case IO_SIGN_COMPLEMENT: return IOBadExp; case IO_SIGN_NONE: sign = IO_SIGN_PLUS; break; case IO_SIGN_MINUS: ++upperLimit; break; default:; } if (tokens->exp > upperLimit) return IOExpOverflow; if (sign < 0) n->exp = -(int)(tokens->exp); else n->exp = tokens->exp; } return Success; } /* create a descriptor from the floating point number given in tokens */ Error str2desc( p_number_desc n, p_itokens tokens) { Error result; _clearnumber(n); result = str2fixp(n, tokens); if (result == Success) result = _exp2desc(n, tokens); if (result != Success) n->prefix.base = IO_BASE_NAN; return result; } Error desc2str( p_otokens tokens, p_number_desc n, int scale) { Error result; result = fixp2str(tokens, n, scale); if (result != Success || _isspecial(n->prefix.base)) return result; tokens->exp = n->exp; return Success; } Error exp2str( p_buffer dest, int exp, char base) { char tmp[BITS_IN_EXP + 3]; int idx = 0; int di = 0; if (exp < 0) exp = -exp; while (exp != 0) { tmp[idx++] = hexdigits[exp % base]; exp /= base; } if (idx == 0) tmp[idx++] = hexdigits[0]; if (dest->sz <= idx) return IOBufferOverflow; for (; --idx >= 0;) dest->buf[di++] = tmp[idx]; dest->buf[di] = 0; return Success; } /* ***************** additional stuff, just to get started *************/ static t_ioparams stdioparams[4] = { {10, 10, '.', "0d", "eE(", " )", "", DECPRECISION}, {16, 10, '.', "0x", "(", ")", "sF", HEXPRECISION}, {2, 10, '.', "0b", "(", ")", "s1", BINPRECISION}, {8, 10, '.', "0o", "(", ")", "s7", OCTPRECISION} }; enum {idzero, idx10, idx16, idx2, idx8, idxcount}; static t_ioparams ioparams[idxcount] = { {IO_BASE_ZERO, IO_BASE_ZERO, '\0', "", "", "", "", 0x7FFFFFFF}, {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0} }; static p_ioparams _defaultbase = NULL; static char _isvalidioparams( p_ioparams param) { return param != NULL && param->base != IO_BASE_DEFAULT; } static void _invalidateioparams( p_ioparams param) { if (param) param->base = IO_BASE_DEFAULT; } p_ioparams _base2ioparams( signed char base) { int idx; switch (base) { case 10: idx = idx10; break; case 16: idx = idx16; break; case 2: idx = idx2; break; case 8: idx = idx8; break; case IO_BASE_ZERO: idx = idzero; break; default: return NULL; } return &ioparams[idx]; } char setioparams( p_ioparams params) { p_ioparams dest; if (!_isvalidioparams(params)) return 0; dest = _base2ioparams(params->base); if (dest == NULL) return 0; *dest = *params; return 1; } char delioparams( signed char base) { p_ioparams dest; dest = _base2ioparams(base); _invalidateioparams(dest); return dest != NULL; } p_ioparams getioparams( signed char base) { p_ioparams result; if (base == IO_BASE_DEFAULT) return _defaultbase; result = _base2ioparams(base); return _isvalidioparams(result)? result : NULL; } static signed char _getdefaultbase() { p_ioparams param; param = getioparams(IO_BASE_DEFAULT); return param == NULL? IO_BASE_DEFAULT : param->base; } signed char setdefaultbase( signed char base) { char result; result = _getdefaultbase(); _defaultbase = _base2ioparams(base); return result; } void float_stdconvert() { int i; for (i = 0; i < 4; ++i) setioparams(&stdioparams[i]); setdefaultbase(10); } const char* basePrefix(char base) { return getioparams(base)->basetag; } static signed char _parsesign( const char** buf) { signed char result; result = IO_SIGN_NONE; if (!_isempty(*buf)) switch (**buf) { case '-': result = IO_SIGN_MINUS; break; case '+': result = IO_SIGN_PLUS; } if (result != IO_SIGN_NONE) (*buf)++; return result; } static signed char _parsebase( const char** buf, char defaultbase) { signed char base; int lg, i; lg = 0; base = IO_BASE_DEFAULT; if (!_isempty(*buf)) for (i = 0; i < idxcount; ++i) { lg = _match(*buf, ioparams[i].basetag); if (lg > 0) { base = ioparams[i].base; break; } } *buf += lg; return base == IO_BASE_DEFAULT? defaultbase : base; } static char _parsecmpl( const char** buf, char base) { int lg; p_ioparams param; param = getioparams(base); lg = 0; if (_isvalidioparams(param)) lg = _match(*buf, param->cmpltag); *buf += lg; return lg > 0; } Error parse( p_itokens tokens, const char** buffer) { p_ioparams params; const char* p; char* expchar; signed char base; int idx; char dot; char* expbegin; char* expend; tokens->fracpart = NULL; tokens->exp = 0; tokens->expsign = IO_SIGN_NONE; tokens->maxdigits = 0; dot = '.'; expbegin = "("; expend = ")"; p = *buffer; tokens->sign = _parsesign(&p); base = _parsebase(&p, _getdefaultbase()); params = getioparams(base); if (params != NULL) { dot = params->dot; if (params->expbegin != NULL) expbegin = params->expbegin; if (params->expend != NULL) expend = params->expend; tokens->maxdigits = params->maxdigits; } else base = 10; tokens->base = base; if (tokens->maxdigits <= 0) tokens->maxdigits = DECPRECISION; if (_parsecmpl(&p, tokens->base)) { if (tokens->sign != IO_SIGN_NONE) return IOInvalidComplement; tokens->sign = IO_SIGN_COMPLEMENT; } tokens->intpart = _scandigits(&p, base); if (*p == dot) { ++p; tokens->fracpart = _scandigits(&p, base); } if (!tokens->intpart && !tokens->fracpart && tokens->sign != IO_SIGN_COMPLEMENT) return IONoSignificand; expchar = strchr(expbegin, *p); if (!_isempty(expchar)) { const char* expptr; int i; int e = 0; int expbase; ++p; idx = expchar - expbegin; tokens->expsign = _parsesign(&p); expbase = _parsebase(&p, base); expptr = _scandigits(&p, expbase); if (!expptr || (*(expend + idx) != ' ' && *(expend + idx) != *p)) return IOBadExp; for (i = 0; i < p-expptr; ++i) { if (!_checkmul(&e, expbase) || !_checkadd(&e, _ascii2digit(*(expptr+i)))) return IOExpOverflow; } tokens->exp = e; } *buffer = p; return Success; } static char _decodesign( signed char s) { switch (s) { case IO_SIGN_PLUS: return '+'; case IO_SIGN_MINUS: return '-'; } return '\0'; } static char* _decodebase( signed char base) { p_ioparams param; param = getioparams(base); if (!_isvalidioparams(param) || _isempty(param->basetag)) return &emptystr; return param->basetag; } static char* _decodecomplement( signed char sign, signed char base) { p_ioparams param; param = getioparams(base); if (sign != IO_SIGN_COMPLEMENT || !_isvalidioparams(param) || _isempty(param->cmpltag)) return &emptystr; return param->cmpltag; } static void _cattoken( char* buf, char* token, char enable) { if (enable && !_isempty(token)) strcat(buf, token); } int cattokens( char* buf, int bufsz, p_otokens tokens, signed char expbase, unsigned flags) { int sz; int fraclg; p_ioparams ioparams; char* expbegin; char* expend; char* cmpltag; char* basetag; char* expbasetag; signed char base; char dot; char cbuf[2]; char printsign; char printbasetag; char printcmpl; char printleading0; char printdot; char printexp; char printexpsign = 0; char printexpbase = 0; char printexpbegin; char printexpend; char exp[BITS_IN_BINEXP+2]; t_buffer expBuf; expBuf.sz = sizeof(exp); expBuf.buf = exp; cbuf[1] = '\0'; fraclg = 0; if (!_isempty(tokens->fracpart.buf)) { fraclg = strlen(tokens->fracpart.buf) - 1; if ((flags & IO_FLAG_SUPPRESS_TRL_ZERO) != 0) while (fraclg >= 0 && tokens->fracpart.buf[fraclg] == '0') --fraclg; ++fraclg; } ioparams = getioparams(IO_BASE_DEFAULT); base = tokens->base; printbasetag = !_isspecial(base) && (flags & IO_FLAG_SUPPRESS_BASETAG) == 0 && (ioparams == NULL || ioparams->base != base); ioparams = getioparams(base); basetag = _decodebase(base); cmpltag = _decodecomplement(tokens->sign, base); expbasetag = NULL; if (base == IO_BASE_DEFAULT) flags |= IO_FLAG_SUPPRESS_DOT | IO_FLAG_SUPPRESS_LDG_ZERO; if ((flags & IO_FLAG_SHOW_BASE) != 0) printbasetag = 1; printcmpl = tokens->sign == IO_SIGN_COMPLEMENT && (flags & IO_FLAG_SUPPRESS_CMPL) == 0; printsign = !printcmpl && tokens->sign != IO_SIGN_NONE && (tokens->sign != IO_SIGN_PLUS || (flags & IO_FLAG_SUPPRESS_PLUS) == 0); printleading0 = _isempty(tokens->intpart.buf) && (flags & IO_FLAG_SUPPRESS_LDG_ZERO) == 0; printdot = fraclg > 0 || (flags & IO_FLAG_SUPPRESS_DOT) == 0; printexp = base != IO_BASE_NAN && base != IO_BASE_ZERO && ((flags & IO_FLAG_SUPPRESS_EXPZERO) == 0 || tokens->exp != 0); if (printexp) { if (expbase < 2) expbase = ioparams->expbase; expbasetag = _decodebase(expbase); printexpsign = tokens->exp < 0 || (flags & IO_FLAG_SUPPRESS_EXPPLUS) == 0; printexpbase = expbasetag != NULL && (flags & IO_FLAG_SUPPRESS_EXPBASE) == 0 && (_isempty(basetag) || strcmp(basetag, expbasetag) != 0); if ((flags & IO_FLAG_SHOW_EXPBASE) != 0) printexpbase = 1; } dot = '.'; expbegin = "("; expend = ")"; if (ioparams != NULL) { dot = ioparams->dot; expbegin = ioparams->expbegin; expend = ioparams->expend; } printexpbegin = *expbegin != '\0'; printexpend = *expend != '\0' && *expend != ' '; sz = 1; if (printsign) sz += 1; if (printbasetag) sz += strlen(basetag); if (printcmpl) sz += strlen(cmpltag); if (printleading0) ++sz; if (!_isempty(tokens->intpart.buf)) sz += strlen(tokens->intpart.buf); if (printdot) sz += 1; sz += fraclg; if (printexp) { exp2str(&expBuf, tokens->exp, expbase); if (printexpbegin) ++sz; if (printexpsign) sz += 1; if (printexpbase) sz += strlen(expbasetag); sz += strlen(expBuf.buf); if (printexpend) ++sz; } if (sz <= bufsz) { *buf = '\0'; cbuf[0] = _decodesign(tokens->sign); _cattoken(buf, cbuf, printsign); _cattoken(buf, basetag, printbasetag); _cattoken(buf, cmpltag, printcmpl); _cattoken(buf, "0", printleading0); _cattoken(buf, tokens->intpart.buf, 1); cbuf[0] = dot; _cattoken(buf, cbuf, printdot); if (fraclg > 0) strncat(buf, tokens->fracpart.buf, fraclg); if (printexp) { cbuf[0] = *expbegin; _cattoken(buf, cbuf, printexpbegin); cbuf[0] = _decodesign(tokens->exp < 0? -1:1); _cattoken(buf, cbuf, printexpsign); _cattoken(buf, expbasetag, printexpbase); strcat(buf, expBuf.buf); cbuf[0] = *expend; _cattoken(buf, cbuf, printexpend); } } return sz; } deepin-calculator-1.0.2/math/floatio.h000066400000000000000000000133731325241207700176560ustar00rootroot00000000000000/* floatio.h: low level conversion, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include #ifndef FLOATIO_H # define FLOATIO_H #define NO_DIGIT 0x7F #define IO_BASE_ZERO 1 #define IO_BASE_NAN 0 #define IO_BASE_DEFAULT (-1) #define IO_SIGN_PLUS 1 #define IO_SIGN_NONE 0 #define IO_SIGN_MINUS (-1) #define IO_SIGN_COMPLEMENT (-2) #define IO_FLAG_SUPPRESS_PLUS 0x001 #define IO_FLAG_SUPPRESS_BASETAG 0x002 #define IO_FLAG_SUPPRESS_CMPL 0x004 #define IO_FLAG_SUPPRESS_LDG_ZERO 0x008 #define IO_FLAG_SUPPRESS_TRL_ZERO 0x010 #define IO_FLAG_SUPPRESS_DOT 0x020 #define IO_FLAG_SUPPRESS_EXPPLUS 0x040 #define IO_FLAG_SUPPRESS_EXPBASE 0x080 #define IO_FLAG_SUPPRESS_EXPZERO 0x100 #define IO_FLAG_SHOW_BASE 0x200 #define IO_FLAG_SHOW_EXPBASE 0x400 #ifdef __cplusplus extern "C"{ #endif typedef struct{ int sz; char* buf; }t_buffer; typedef t_buffer* p_buffer; /* t_seq_desc describes the format of a sequence of digits. leadingSignDigits are the count of leading zeros (or for two's complement, F's, 7's or 1's), trailing0 are the number of zeros at the end of the sequence and digits are the total count of digits in the sequence. If a sequence contains only zeros, in some contexts, they are counted as sign digits, in others they are trailing zeros. base is the number base the sequence is coded in (one of 2, 8, 10 or 16) and is reserved for callback. */ typedef struct{ int leadingSignDigits; int trailing0; int digits; int base; void* param; } t_seq_desc; typedef t_seq_desc* p_seq_desc; /* the number of digits not being a leading sign digit or a trailing zero */ int _significantdigits(p_seq_desc n); /* sequences of digits can be encoded in various ways (ASCII, bc_num style, packed and so on). In order to access a single digit, a getter has to be supplied for each encoding. This is the common interface of these getters. ofs is the index of the digit in the sequence, the first (most significant) having an index 0. The getter should return a sign digit (mostly 0) for negative indices and 0 for indices greator or equal to the length of the sequence. Instances of t_getdigit usually access the param field of n to find the data structure where the digits are encoded in */ typedef char (*t_getdigit)(int ofs, p_seq_desc param); /* list of tokens that are created in an output process. Instead of returning a single ASCII string, all parts of a number are kept in separate places, so a post-processor can reorder or beautify them */ typedef struct{ signed char sign; signed char base; t_buffer intpart; t_buffer fracpart; int exp; } t_otokens; typedef t_otokens* p_otokens; /* list of tokens that are sources in an input process. Instead of using a single ASCII string, all parts of a number are kept in separate places, stripped off all grammar related information. The tokens need not be 0 terminated, as long as the token is delimited by something not mistaken as a part of it. */ typedef struct{ signed char sign; signed char base; const char* intpart; const char* fracpart; signed char expsign; unsigned exp; unsigned maxdigits; } t_itokens; typedef t_itokens* p_itokens; typedef struct{ t_seq_desc seq; t_getdigit getdigit; } t_ext_seq_desc; typedef t_ext_seq_desc* p_ext_seq_desc; typedef struct{ signed char sign; signed char base; } t_prefix; typedef t_prefix* p_prefix; typedef struct{ t_prefix prefix; t_ext_seq_desc intpart; t_ext_seq_desc fracpart; int exp; } t_number_desc; typedef t_number_desc* p_number_desc; void _clearnumber(p_number_desc n); Error str2desc(p_number_desc n, p_itokens tokens); Error desc2str(p_otokens tokens, p_number_desc n, int scale); Error exp2str(p_buffer dest, int exp, char base); /*------------ additional stuff ------------------*/ /* t_ioparams is a data structure that contains all necessary information to convert an ASCII character encoded number into a t_token and vice versa. Most information is grammar related like dot, basetag and so on. Others like maxdigits describe general limits of floatnums. */ typedef struct{ signed char base; signed char expbase; char dot; char* basetag; char* expbegin; char* expend; char* cmpltag; unsigned maxdigits; } t_ioparams; typedef t_ioparams* p_ioparams; const char* basePrefix(char base); Error parse(p_itokens tokens, const char** buf); int cattokens(char* buf, int bufsz, p_otokens tokens, signed char expbase, unsigned flags); void float_stdconvert(); char setioparams(p_ioparams params); char delioparams(signed char base); p_ioparams getioparams(signed char base); signed char setdefaultbase(signed char base); #ifdef __cplusplus } #endif #endif /* FLOATIO_H */ deepin-calculator-1.0.2/math/floatipower.c000066400000000000000000000064451325241207700205510ustar00rootroot00000000000000/* floatpower.c: power operation, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatipower.h" #include "floatconst.h" #include "floatcommon.h" #include "floatlong.h" /* for radix conversion, we need to get a result, even though it might slightly overflow or underflow. That is why we keep the exponent separate. For limited exponents (< 1024) the relative error for a 100 digit calculation is < 1e-99 x != 0 */ char _raiseposi( floatnum x, int* expx, unsigned exponent, int digits) { int exppwr, extra; floatstruct pwr; float_create(&pwr); float_move(&pwr, x); exppwr = float_getexponent(&pwr); float_setexponent(&pwr, 0); if ((exponent & 1) != 0) { float_copy(x, &pwr, digits+1); *expx = exppwr; } else { float_copy(x, &c1, EXACT); *expx = 0; } extra = _findfirstbit(exponent)/3+1; while((exponent >>= 1) != 0) { float_mul(&pwr, &pwr, &pwr, digits+extra); if (!_checkadd(&exppwr, exppwr)) break; exppwr += float_getexponent(&pwr); float_setexponent(&pwr, 0); if((exponent & 1) != 0) { float_mul(x, x, &pwr, digits+extra); *expx += exppwr + float_getexponent(x); float_setexponent(x, 0); } } float_free(&pwr); return exponent == 0; } char _raiseposi_( floatnum x, unsigned exponent, int digits) { int exp; char result; result = _raiseposi(x, &exp, exponent, digits); float_setexponent(x, exp); return result; } /* raises a non-zero x to the exponent-th power */ char _raisei( floatnum x, int exponent, int digits) { int expx; signed char sgn; char negexp; switch (exponent) { case 0: float_copy(x, &c1, EXACT); /* fall through */ case 1: return 1; } if (float_getlength(x) == 1 && float_getdigit(x, 0) == 1) { /* power of ten */ if (!_checkmul(&exponent, float_getexponent(x)) || exponent < EXPMIN || exponent > EXPMAX) return 0; sgn = float_getsign(x) < 0? -(exponent & 1) : 1; float_setexponent(x, exponent); float_setsign(x, sgn); return 1; } negexp = exponent < 0; if (negexp) exponent = -exponent; if (!_raiseposi(x, &expx, exponent, digits) || expx < EXPMIN || expx > EXPMAX) return 0; float_setexponent(x, expx); return negexp? float_reciprocal(x, digits) : 1; } deepin-calculator-1.0.2/math/floatipower.h000066400000000000000000000026731325241207700205550ustar00rootroot00000000000000/* floatpower.h: power operation, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATIPOWER_H # define FLOATIPOWER_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif char _raiseposi_(floatnum x, unsigned exponent, int digits); char _raiseposi(floatnum x, int* expx, unsigned exponent, int digits); char _raisei(floatnum x, int exponent, int digits); #ifdef __cplusplus } #endif #endif /* FLOATIPOWER_H */ deepin-calculator-1.0.2/math/floatlog.c000066400000000000000000000304261325241207700200210ustar00rootroot00000000000000/* floatlog.c: logarithm and friends, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatlog.h" #include "floatconst.h" #include "floatcommon.h" #include "floatseries.h" typedef struct { char c2; char c3; char c5; char c7; char c10; } _lincomb; static _lincomb _lincombtbl[] = { {0,3,3,2,5},{12,4,0,2,7},{4,0,0,0,1},{0,2,2,1,3},{13,3,0,1,6}, /* -.40 */ {7,5,0,2,6},{10,1,0,2,5},{4,3,0,3,5},{1,6,0,0,3},{4,2,0,0,2}, /* -.35 */ {0,4,2,1,4},{1,0,0,1,1},{0,9,0,1,5},{3,5,0,1,4},{6,1,0,1,3}, /* -.30 */ {0,3,0,2,3},{8,6,0,1,6},{11,2,0,1,5},{0,6,2,1,5},{22,1,0,0,7}, /* -.25 */ {9,5,0,0,5},{0,0,2,2,3},{0,5,1,0,3},{2,1,0,0,1},{0,3,4,1,5}, /* -.20 */ {0,1,8,0,6},{0,3,3,3,6},{5,6,0,2,6},{8,2,0,2,5},{0,13,0,1,7}, /* -.15 */ {12,3,0,0,5},{0,7,1,0,4},{0,2,1,4,5},{0,7,0,2,5},{3,3,0,2,4}, /* -.10 */ {20,0,0,0,6},{7,4,0,0,4},{10,0,0,0,3},{8,4,0,2,6},{0,0,0,0,0}, /* -.05 */ {0,0,0,0,0},{0,9,1,0,5},{13,5,0,2,8},{9,3,0,1,5},{0,7,4,1,7}, /* 0.00 */ {10,3,0,3,7},{0,1,5,0,4},{0,12,2,1,8},{10,2,0,0,4},{8,6,0,2,7},/* 0.05 */ {8,1,0,6,8},{7,0,0,1,3},{5,4,0,3,6},{22,1,0,1,8},{2,7,0,0,4}, /* 0.10 */ {2,2,0,4,5},{0,0,2,3,4},{0,5,1,1,4},{0,3,5,0,5},{14,6,0,1,8}, /* 0.15 */ {10,4,0,0,5},{3,1,0,3,4},{4,6,0,1,5},{0,4,0,0,2},{14,0,0,2,6}, /* 0.20 */ {0,13,1,0,7},{8,2,0,3,6},{4,0,0,2,3},{2,4,0,4,6},{0,2,2,3,5}, /* 0.25 */ {0,0,6,2,6},{0,5,5,0,6},{23,2,0,0,8},{0,1,2,0,2},{17,4,0,1,8}, /* 0.30 */ {0,10,3,0,7},{11,6,0,2,8},{4,3,0,5,7},{14,2,0,2,7},{10,0,0,1,4},/* 0.35 */ {8,4,0,3,7},{1,1,0,6,6},{11,0,0,3,6},{12,5,0,1,7},{2,1,0,8,8}, /* 0.40 */ {15,1,0,1,6},{0,7,5,0,7},{6,2,0,6,8},{2,0,0,5,5},{1,14,0,1,8}, /* 0.45 */ {0,12,3,0,8},{20,2,0,1,8},{0,8,0,0,4},{14,4,0,2,8},{3,4,0,0,3},/* 0.50 */ {0,1,4,3,6},{6,0,0,0,2},{4,4,0,2,5},{0,2,0,1,2},{8,0,1,2,5}, /* 0.55 */ {8,5,0,0,5},{15,3,0,1,7},{0,9,5,0,8},{0,0,3,2,4},{0,5,2,0,4}, /* 0.60 */ {5,3,0,1,4},{0,0,2,4,5},{13,6,0,0,7},{3,2,0,7,8},{16,2,0,0,6}, /* 0.65 */ {0,1,9,0,7},{3,6,0,0,4},{10,4,0,1,6},{0,0,0,8,7},{13,0,0,1,5}, /* 0.70 */ {0,6,7,0,8},{0,4,0,1,3},{0,2,4,0,4},{3,0,0,1,2},{15,5,0,1,8}, /* 0.75 */ {8,2,0,4,7},{2,9,0,1,6},{4,0,0,3,4},{2,4,0,5,7},{12,3,0,2,7}, /* 0.80 */ {1,3,0,0,2},{0,0,6,3,7},{6,5,0,3,7},{16,4,0,0,7},{0,3,9,0,8}, /* 0.85 */ {0,1,2,1,3},{10,6,0,1,7},{0,2,0,8,8},{0,10,3,1,8},{0,1,1,3,4}, /* 0.90 */ {9,0,0,0,3},{4,3,0,6,8},{0,4,4,0,5},{8,9,0,0,7},{10,0,0,2,5} /* 0.95 */ }; /* artanh x and ln(x+1) are closely related. Evaluate the logarithm using the artanh series, which converges twice as fast as the logarithm series. With 100 digits, if -0.0198 <= x <= 0.02, the relative error is less than 5.0e-100, or at most 1 unit in the 100th place */ void _lnxplus1near0( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); float_add(&tmp, &c2, x, digits); float_div(x, x, &tmp, digits); artanhnear0(x, digits); float_add(x, x, x, EXACT); float_free(&tmp); } /* helpers */ static void _addcoef( floatnum x, int coef, floatnum cnst, int digits) { floatstruct tmp; if (coef != 0) { float_create(&tmp); float_muli(&tmp, cnst, coef, digits); float_add(x, x, &tmp, digits); float_free(&tmp); } } static int _factor( int idx) { int factor; int i; factor = 1; for (i = _lincombtbl[idx].c2; --i >= 0;) factor *= 2; for (i = _lincombtbl[idx].c3; --i >= 0;) factor *= 3; for (i = _lincombtbl[idx].c5; --i >= 0;) factor *= 5; for (i = _lincombtbl[idx].c7; --i >= 0;) factor *= 7; return factor; } static void _lnguess( floatnum dest, int digits, int idx) { _addcoef(dest, _lincombtbl[idx].c2-_lincombtbl[idx].c5, &cLn2, digits); _addcoef(dest, _lincombtbl[idx].c3, &cLn3, digits); _addcoef(dest, _lincombtbl[idx].c7, &cLn7, digits); _addcoef(dest, _lincombtbl[idx].c5-_lincombtbl[idx].c10, &cLn10, digits); } /* reduces x using a special factor whose prime factors are 2, 3, 5 and 7 only. x is multiplied by this factor, yielding a value near a power of ten. Then x is divided by this power of ten. The logarithm of this factor is returned in lnguess. Valid for -0.4 <= x < 1. Relative error < 5e-100 for 100 digit result. This algorithm reduces x to a value < 0.01, which is appropriately small for submitting to a series evaluation */ void _lnreduce( floatnum x, floatnum lnguess, int digits) { floatstruct tmp1, tmp2; int idx; int expx; signed char pos; float_setzero(lnguess); expx = float_getexponent(x); if (expx < -2) return; float_create(&tmp1); float_create(&tmp2); idx = leadingdigits(x, 3 + expx) + 39; if (idx < 0) idx = 0; pos = idx >= 40? 1 : 0; idx += pos; float_setinteger(&tmp1, _factor(idx)); float_setexponent(&tmp1, -pos); float_sub(&tmp1, &tmp1, &c1, EXACT); float_mul(&tmp2, x, &tmp1, digits); float_add(&tmp1, &tmp1, &tmp2, digits+1); float_add(x, x, &tmp1, digits); _lnguess(lnguess, digits+4, idx); float_free(&tmp1); float_free(&tmp2); return; } /* for -0.4 <= x < 1.0 */ void _lnxplus1lt1( floatnum x, int digits) { floatstruct lnfactor; float_create(&lnfactor); _lnreduce(x, &lnfactor, digits); _lnxplus1near0(x, digits); float_sub(x, x, &lnfactor, digits+1); float_free(&lnfactor); } /* the general purpose routine evaluating ln(x) for all positive arguments. It uses multiplication and division to reduce the argument to a value near 1. The factors are always small, so these operations do not take much time. -- One often sees an argument reduction by taking the square root several times in succession. But the square root is slow in number.c, so we avoid it best. -- Super-fast algorithm like the AGM based ones, do not pay off for limited lengths because of the same reason: They require taking square roots several times. A test showed, a hundred digits calculation using AGM is 8 times slower than the algorithm here. For extreme precision, of course, AGM will be superior. The relative error seems to be less than 7e-101 for 100-digits computations */ void _ln( floatnum x, int digits) { floatstruct tmp; int coef10; char coef3; char dgt; float_create(&tmp); coef10 = float_getexponent(x); /* reducing the significand to 0.6 <= x < 2 by simple multiplication */ dgt = leadingdigits(x, 1); coef3 = 0; if (dgt == 1) float_setexponent(x, 0); else { ++coef10; float_setexponent(x, - 1); coef3 = (dgt < 6); if (coef3) float_mul(x, x, &c3, digits+1); } float_sub(x, x, &c1, digits+1); _lnxplus1lt1(x, digits); if (coef10 != 0) { float_muli(&tmp, &cLn10, coef10, digits+1); float_add(x, x, &tmp, digits+1); } if (coef3) float_sub(x, x, &cLn3, digits); float_free(&tmp); } void _lnxplus1( floatnum x, int digits) { if (float_cmp(x, &cMinus0_4) >= 0 && float_cmp(x, &c1) < 0) _lnxplus1lt1(x, digits); else { float_add(x, x, &c1, digits+1); _ln(x, digits); } } /* The artanh function has a pole at x == 1. For values close to 1 the general purpose evaluation is too unstable. We use a dedicated algorithm here to get around the problems. Avoid using this function for values of x > 0.5, _artanh is the better choice then. Values near the other pole of artanh at -1 can be derived from this function using artanh(-1+x) = -artanh(1-x). For x < 0.5 and a 100-digit computation, the maximum relative error is in the order of 1e-99 */ void _artanh1minusx( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); float_sub(&tmp, &c2, x, digits); float_div(x, &tmp, x, digits); _ln(x, digits); float_mul(x, x, &c1Div2, digits); float_free(&tmp); } /* designed for |x| <= 0.5. The evaluation is not symmetric with respect to 0, i.e. it might be -artanh x != artanh -x. The difference is in the order of the last digit, of course. Evaluation of positive values yield a slightly better relative error than that of negative values. The maximum relative error is the maximum of that of artanhnear0 and 1e-99 */ void _artanhlt0_5( floatnum x, int digits) { floatstruct tmp; if (float_getexponent(x) < -2 || float_iszero(x)) artanhnear0(x, digits); else { float_create(&tmp); float_sub(&tmp, &c1, x, digits+1); float_add(x, x, x, digits); float_div(x, x, &tmp, digits); _lnxplus1(x, digits); float_mul(x, x, &c1Div2, digits); float_free(&tmp); } } /* the general purpose routine for evaluating artanh. The evaluation is symmetric with respect to 0, i.e. it is always -artanh(x) == artanh -x. Valid for |x| < 1, but unstable for |x| approx. == 1 */ void _artanh( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) <= 0) _artanhlt0_5(x, digits); else { float_sub(x, &c1, x, digits+1); _artanh1minusx(x, digits); } float_setsign(x, sgn); } /* evaluates ln(2*x), the asymptotic function of arsinh and arcosh for large x */ static void _ln2x( floatnum x, int digits) { _ln(x, digits); float_add(x, &cLn2, x, digits); } /* valid for all x. The relative error is less than 1e-99. The evaluation is symmetric with respect to 0: arsinh -x == - arsinh x */ void _arsinh( floatnum x, int digits) { floatstruct tmp; int expxsqr; signed char sgn; expxsqr = 2*float_getexponent(x)+2; /* for extreme small x, sqrt(1+x*x) is approx == 1 + x*x/2 - x^4/8, so arsinh x == ln(1 + x + x*x/2 - x^4/8 +...) approx == x - x*x*x/6 + ... If we approximate arsinh x by x, the relative error is roughly |x*x/6|. This is less than acceptable 10^(-), if log(x*x) < - */ if (expxsqr < -digits || float_iszero(x)) return; float_create(&tmp); /* arsinh -x = -arsinh x, so we can derive the arsinh for negative arguments from that of positive arguments */ sgn = float_getsign(x); float_abs(x); if (expxsqr-2 > digits) /* for very large x, use the asymptotic formula ln(2*x) */ _ln2x(x, digits); else { float_mul(&tmp, x, x, digits + (expxsqr>=0? 0 : expxsqr)); float_add(&tmp, &tmp, &c1, digits+1); float_sqrt(&tmp, digits); if (float_getexponent(x) < 0) { /* for small x, use arsinh x == artanh (x/sqrt(1+x*x)). Stable for x < 1, but not for large x*/ float_div(x, x, &tmp, digits); _artanh(x, digits+1); } else { /* arsinh x = ln(x+sqrt(1+x*x)), stable for x >= 1, but not for small x */ float_add(x, x, &tmp, digits); _ln(x, digits); } } float_setsign(x, sgn); float_free(&tmp); } /* arcosh(x+1), x >= 0, is the stable variant of arcosh(x), x >= 1. The relative error is less than 1e-99. */ void _arcoshxplus1( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); if (2*float_getexponent(x) > digits) { /* for very large x, use the asymptotic formula ln(2*(x+1)) */ float_add(x, x, &c1, digits+1); _ln2x(x, digits); } else { /* arcosh(x+1) = ln(1+(x+sqrt(x*(x+2)))), stable for all positive x, except for extreme large x, where x*(x+2) might overflow */ /* get sinh(arcosh (1+x)) = sqrt(x*(x+2)) */ float_add(&tmp, x, &c2, digits); float_mul(&tmp, x, &tmp, digits); float_sqrt(&tmp, digits); float_add(x, x, &tmp, digits); _lnxplus1(x, digits); } float_free(&tmp); } deepin-calculator-1.0.2/math/floatlog.h000066400000000000000000000032531325241207700200240ustar00rootroot00000000000000/* floatlog.h: logarithms and friends, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATLOG_H # define FLOATLOG_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif void _lnxplus1near0(floatnum x, int digits); void _lnreduce(floatnum x, floatnum lnguess, int digits); void _lnxplus1lt1(floatnum x, int digits); void _ln(floatnum x, int digits); void _lnxplus1(floatnum x, int digits); void _artanh1minusx(floatnum x, int digits); void _artanhlt0_5(floatnum x, int digits); void _artanh(floatnum x, int digits); void _arsinh(floatnum x, int digits); void _arcoshxplus1(floatnum x, int digits); #ifdef __cplusplus } #endif #endif /* FLOATLOG_H */ deepin-calculator-1.0.2/math/floatlogic.c000066400000000000000000000115021325241207700203270ustar00rootroot00000000000000/* floatlogic.c: logic functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatlogic.h" #include "floatconst.h" #define MAXIDX ((LOGICRANGE-1) / BITS_IN_UNSIGNED) #define SIGNBIT (LOGICRANGE - 1 - MAXIDX * BITS_IN_UNSIGNED) static void _zeroextend( t_longint* longint) { int idx; idx = longint->length - 1; for (; ++idx <= (int)MAXIDX;) longint->value[idx] = 0; } signed char _signof( t_longint* longint) { return (longint->value[MAXIDX] & (1 << SIGNBIT)) != 0? -1:1; } static char _signextend( t_longint* longint) { unsigned mask; signed char sign; sign = _signof(longint); mask = (~0) << SIGNBIT; if (sign < 0) longint->value[MAXIDX] |= mask; else longint->value[MAXIDX] &= ~mask; return sign; } static void _neg( t_longint* longint) { int idx = -1; const int maxidx = MAXIDX; while (++idx <= maxidx && longint->value[idx] == 0); if (idx <= maxidx) longint->value[idx] = - longint->value[idx]; while (++idx <= maxidx) longint->value[idx] = ~longint->value[idx]; } char _floatnum2logic( t_longint* longint, cfloatnum x) { floatstruct tmp; int digits; digits = float_getexponent(x)+1; if (float_iszero(x) || digits <= 0) { longint->length = 1; longint->value[0] = 0; } else { if (digits > MATHPRECISION) return 0; float_create(&tmp); /* floatnum2longint rounds, we have to truncate first */ float_copy(&tmp, x, digits); if (float_getsign(x) < 0) float_add(&tmp, &tmp, &c1, EXACT); _floatnum2longint(longint, &tmp); float_free(&tmp); if (_bitlength(longint) > LOGICRANGE) return 0; } _zeroextend(longint); if (float_getsign(x) < 0) _not(longint); return 1; } void _logic2floatnum( floatnum f, t_longint* longint) { int idx; signed char sign; sign = _signextend(longint); if (sign < 0) _neg(longint); idx = MAXIDX; while (idx >= 0 && longint->value[idx] == 0) --idx; if (idx < 0) longint->length = 0; else longint->length = idx + 1; _longint2floatnum(f, longint); float_setsign(f, sign); } void _not( t_longint* longint) { int idx; for (idx = -1; ++idx <= (int)MAXIDX;) longint->value[idx] = ~(longint->value[idx]); } void _and( t_longint* x1, t_longint* x2) { int idx; for (idx = -1; ++idx <= (int)MAXIDX;) x1->value[idx] = x1->value[idx] & x2->value[idx]; } void _or( t_longint* x1, t_longint* x2) { int idx; for (idx = -1; ++idx <= (int)MAXIDX;) x1->value[idx] = x1->value[idx] | x2->value[idx]; } void _xor( t_longint* x1, t_longint* x2) { int idx; for (idx = -1; ++idx <= (int)MAXIDX;) x1->value[idx] = x1->value[idx] ^ x2->value[idx]; } void _shr( t_longint* x, unsigned shift) { int idx; const unsigned sign = _signof(x) < 0? ~0 : 0; const int moves = shift/BITS_IN_UNSIGNED; const int maxidx = MAXIDX; if (moves > 0) { shift -= moves * BITS_IN_UNSIGNED; for (idx = moves-1; ++idx <= maxidx;) x->value[idx-moves] = x->value[idx]; idx = MAXIDX - moves + 1; if (idx < 0) idx = 0; for (; idx <= maxidx; ++idx) x->value[idx] = sign; } if (shift > 0) { for (idx = -1; ++idx < maxidx;) x->value[idx] = _longshr(x->value[idx], x->value[idx+1], shift); x->value[MAXIDX] = _longshr(x->value[MAXIDX], sign, shift); } } void _shl( t_longint* x, unsigned shift) { int moves, idx; moves = shift/BITS_IN_UNSIGNED; if (moves > 0) { shift -= moves * BITS_IN_UNSIGNED; for (idx = MAXIDX; idx >= moves; --idx) x->value[idx] = x->value[idx-moves]; if (moves > (int)MAXIDX) moves = MAXIDX+1; for (idx = -1; ++idx < moves;) x->value[idx] = 0; } if (shift > 0) { for (idx = MAXIDX; idx > 0; --idx) x->value[idx] = _longshl(x->value[idx-1], x->value[idx], shift); x->value[0] <<= shift; } } deepin-calculator-1.0.2/math/floatlogic.h000066400000000000000000000031731325241207700203410ustar00rootroot00000000000000/* floatlogic.h: logic functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATLOGIC_H # define FLOATLOGIC_H #include "floatconvert.h" #ifdef __cplusplus extern "C" { #endif char _canconvert(cfloatnum x); char _floatnum2logic(t_longint* longint, cfloatnum x); void _logic2floatnum(floatnum f, t_longint* longint); void _not(t_longint* longint); void _and(t_longint* x1, t_longint* x2); void _or(t_longint* x1, t_longint* x2); void _xor(t_longint* x1, t_longint* x2); void _shr(t_longint* x, unsigned shift); void _shl(t_longint* x, unsigned shift); #ifdef __cplusplus } #endif #endif /* FLOATLOGIC_H */ deepin-calculator-1.0.2/math/floatlong.c000066400000000000000000000141161325241207700201750ustar00rootroot00000000000000/* floatlong.c: portable double size integer arithmetic. */ /* Copyright (C) 2007 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatlong.h" #define HALFSIZE (sizeof(unsigned) * 4) #define LOWMASK ((1 << HALFSIZE) - 1) #define MSB (1 << (2*HALFSIZE-1)) /*************** functions handling a single unsigned ********************/ int _findfirstbit( unsigned value) { int result; result = -1; while (value != 0) { value >>= 1; ++result; } return result; } /* pre: value != 0 */ static int _revfindfirstbit( unsigned value) { int result; result = 0; while ((value & 1) == 0) { value >>= 1; ++result; } return result; } /******************* double unsigned functions ********************/ static void _longsplit( unsigned value, unsigned* low, unsigned* high) { *high = value >> HALFSIZE; *low = value & LOWMASK; } static unsigned _longcat( unsigned low, unsigned high) { return (high << HALFSIZE) + low; } char _longadd( unsigned* s1, unsigned* s2) { unsigned s1h, s1l, s2h, s2l; _longsplit(*s1, &s1l, &s1h); _longsplit(*s2, &s2l, &s2h); s1l += s2l; _longsplit(s1l, &s1l, &s2l); s1h += s2h + s2l; _longsplit(s1h, &s1h, s2); *s1 = _longcat(s1l, s1h); return *s2 == 0; } char _longmul( unsigned* f1, unsigned* f2) { unsigned f1h, f1l, f2h, f2l; _longsplit(*f1, &f1l, &f1h); _longsplit(*f2, &f2l, &f2h); *f1 = f1l * f2l; *f2 = f1h * f2h; f1l *= f2h; f2l *= f1h; _longadd(&f1l, &f2l); _longsplit(f1l, &f1l, &f1h); f1l <<= HALFSIZE; _longadd(f1, &f1l); *f2 += f1l + (f2l << HALFSIZE) + f1h; return *f2 == 0; } unsigned _longshr( unsigned low, unsigned high, char shift) { if (shift == 0) return low; return (low >> shift) | (high << ((2*HALFSIZE)-shift)); } unsigned _longshl( unsigned low, unsigned high, char shift) { if (shift == 0) return high; return (low >> ((2*HALFSIZE)-shift)) | (high << shift); } /***************** unsigned array functions *****************/ unsigned _longarrayadd( unsigned* uarray, int lg, unsigned incr) { for(; lg-- > 0 && incr != 0;) _longadd(uarray++, &incr); return incr; } unsigned _longarraymul( unsigned* uarray, int lg, unsigned factor) { unsigned ovfl, carry; carry = 0; ovfl = 0; for (; lg-- > 0;) { carry += ovfl; ovfl = factor; _longmul(uarray, &ovfl); _longadd(uarray++, &carry); } return carry + ovfl; } unsigned _bitsubstr( unsigned* uarray, int ofs) { int idx; if (ofs <= 0) return *uarray << -ofs; idx = ofs / BITS_IN_UNSIGNED; return _longshr(*(uarray+idx), *(uarray+idx+1), ofs - idx * BITS_IN_UNSIGNED); } void _orsubstr( unsigned* uarray, int bitofs, unsigned value) { int idx; int ofs; idx = bitofs / BITS_IN_UNSIGNED; ofs = bitofs - idx * BITS_IN_UNSIGNED; if (ofs == 0) *(uarray + idx) |= value; else { *(uarray + idx) |= value << ofs; *(uarray + idx + 1) |= value >> (BITS_IN_UNSIGNED - ofs); } } /**************** longint functions ****************/ char _isfull( t_longint* l) { return l->length >= (int)UARRAYLG - 1; } unsigned _bitlength( t_longint* l) { if (l->length == 0) return 0; return (l->length - 1) * BITS_IN_UNSIGNED + _findfirstbit(l->value[l->length-1]) + 1; } unsigned _lastnonzerobit( t_longint* l) { int i; if (l->length == 0) return -1; i = -1; for (; ++i < l->length && l->value[i] == 0;); return i * BITS_IN_UNSIGNED + _revfindfirstbit(l->value[i]); } unsigned _longintadd( t_longint* l, unsigned summand) { unsigned ovfl; ovfl = _longarrayadd(l->value, l->length, summand); if (ovfl != 0 && !_isfull(l)) { l->value[l->length] = ovfl; ++l->length; ovfl = 0; } return ovfl; } unsigned _longintmul( t_longint* l, unsigned factor) { unsigned ovfl; ovfl = _longarraymul(l->value, l->length, factor); if (ovfl != 0 && !_isfull(l)) { l->value[l->length] = ovfl; ++l->length; ovfl = 0; } return ovfl; } char _longintsetsize( t_longint* l, unsigned bitlength) { int i; if (bitlength == 0) l->length = 0; else l->length = (bitlength - 1) / BITS_IN_UNSIGNED + 1; if (l->length >= (int)UARRAYLG) return 0; for(i = l->length; i >= 0; --i) l->value[i] = 0; return 1; } /**************** overflow checking integer functions *************/ char _checkadd( int* s1, int s2) { unsigned u1, u2; if ((*s1 < 0) ^ (s2 < 0)) { /* you can always add summands of opposite sign */ *s1 += s2; return 1; } if (s2 < 0) { u1 = -*s1; u2 = -s2; _longadd(&u1, &u2); *s1 = -(int)u1; return u2 == 0 && *s1 < 0; } u1 = *s1; u2 = s2; _longadd(&u1, &u2); *s1 = u1; return *s1 >= 0; } char _checkmul( int* f1, int f2) { unsigned x1, x2; signed char sgn = 1; const unsigned msb = MSB; if (*f1 >= 0) x1 = *f1; else { sgn = -1; x1 = -*f1; } if (f2 >= 0) x2 = f2; else { sgn = -sgn; x2 = -f2; } _longmul(&x1, &x2); if (sgn < 0) { *f1 = -(int)x1; return (x2 == 0 && x1 <= msb); } *f1 = (int)x1; return (x2 == 0 && x1 < msb); } deepin-calculator-1.0.2/math/floatlong.h000066400000000000000000000045221325241207700202020ustar00rootroot00000000000000/* floatlong.h: portable double size integer arithmetic */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATLONG_H # define FLOATLONG_H #include "floatconfig.h" #ifdef __cplusplus extern "C" { #endif #define BITS_IN_UNSIGNED (sizeof(unsigned)*8) /* one unsigned extra, so that _bitsubstr() does not access parts outside of t_uarray */ #define UARRAYLG ((8305*(MATHPRECISION+5) + 1)/20000/sizeof(unsigned) + 2) typedef unsigned t_uarray[UARRAYLG]; typedef struct{ int length; t_uarray value; } t_longint; int _findfirstbit(unsigned value); char _longadd(unsigned* s1, unsigned* s2); char _longmul(unsigned* f1, unsigned* f2); char _checkadd(int* s1, int s2); char _checkmul(int* f1, int f2); unsigned _longshr(unsigned low, unsigned high, char shift); unsigned _longshl(unsigned low, unsigned high, char shift); unsigned _longarrayadd(unsigned* uarray, int lg, unsigned incr); unsigned _longarraymul(unsigned* uarray, int lg, unsigned factor); void _orsubstr(unsigned* uarray, int bitofs, unsigned value); unsigned _bitsubstr(unsigned* uarray, int ofs); unsigned _bitlength(t_longint* l); unsigned _lastnonzerobit(t_longint* l); char _longintsetsize(t_longint* l, unsigned bitlength); unsigned _longintadd(t_longint* l, unsigned summand); unsigned _longintmul(t_longint* l, unsigned factor); #ifdef __cplusplus } #endif #endif /* FLOATLONG_H */ deepin-calculator-1.0.2/math/floatnum.c000066400000000000000000001176621325241207700200470ustar00rootroot00000000000000/* floatnum.c: Arbitrary precision floating point numbers, based on bc. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ /* a floating point engine based on bc's decimal fix point arithmetic. The speed is not overwhelming, but sufficient for calculators with limited demands. As bc's number.c is a portable engine, this should be portable as well. */ #include "floatnum.h" #include "floatlong.h" #include #include #define NOSPECIALVALUE 1 int maxdigits = MAXDIGITS; Error float_error; int expmax = EXPMAX; int expmin = EXPMIN; /* general helper routines */ static int _max(int x, int y) { return x > y? x : y; } static int _min(int x, int y) { return x < y? x : y; } /* the return value points to the first character different from accept. */ const char* _memskip( const char* buf, const char* end, char accept) { for(--buf; ++buf != end && *buf == accept;); return buf; } /* scans a value in a bc-num (or part of it) for the first occurrence of a digit *different* from . The scan is limited to bytes. Returns the offset of the matching byte, or , if none was found */ static int _scan_digit( const char*p, int count, char digit) { const char* ps; ps = p; for (; count-- > 0 && *p == digit; ++p); return p - ps; } /* bc_num primitives */ #define _scaleof(f) (f->significand->n_scale) #define _lenof(f) (f->significand->n_len) #define _valueof(f) (f->significand->n_value) #define _digit(f, offset) (*(_valueof(f) + offset)) #define _setscale(f, value) (_scaleof(f) = value) /* converts floatnum's sign encodings (+1, -1) to bc_num sign encoding (PLUS, MINUS) */ static void _setsign( floatnum f, signed char value) { f->significand->n_sign = value < 0? MINUS : PLUS; #ifdef FLOATDEBUG f->value[0] = value < 0? '-' : '+'; #endif } /* modifies a bc_num significand such that the last (existing) digits of its value are not visible to bc_num operations any more. A negative reverts this operation (unhide). pre: <= n_scale*/ static void _hidelast( floatnum f, int count) { f->significand->n_scale -= count; } /* modifies a bc_num significand such that the first (existing) digits of its value are not visible to bc_num operations any more. A negative reverts this operation (unhide). pre: <= n_scale*/ static void _hidefirst( floatnum f, int count) { f->significand->n_value += count; f->significand->n_scale -= count; } /* Usually, significands are normalized, which means they fulfill 1 <= x < 10. This operation moves the decimal point places to the right, effectively multiplying the significand by a power of 10. A negative reverts such an operation. pre: < n_scale */ static void _movepoint( floatnum f, int digits) { f->significand->n_len += digits; f->significand->n_scale -= digits; } /* floatstruct primitives */ /* a quick check for NaN and 0 */ static char _is_special( cfloatnum f) { return f->significand == NULL; } /* creates a shallow working copy of in , using b as a container for the significand. On return, is equal in value to . may then be modified freely in the course of an operation, without effecting source, *except* that the digits in *(dest->significand->n_value) have to be retained (or restored). must *never* be the destination of a float_xxx operation, in particiular, it must not be freed. Neither must b be modified (or freed) in a bc_num operation */ static void _copyfn( floatnum dest, cfloatnum source, bc_num b) { *dest = *source; if (!_is_special(source)) { *b = *(source->significand); b->n_ptr = 0; dest->significand = b; } } /* If you want to execute a bc_num operation to a limited scale, it is a waste of computation time to pass operands with a longer scale, because bc lets the operand's scale override your limit. This function hides superfluous digits from bc, returning the original scale for restoring purposes */ static int _limit_scale( floatnum f, int newscale) { int oldscale; oldscale = _scaleof(f); _setscale(f, _min(oldscale, newscale)); return oldscale; } /*============================ floatnum routines ===================*/ int float_getrange() { return expmax; } int float_getprecision() { return maxdigits; } int float_setrange( int maxexp) { int result; result = expmax; expmax = _max(_min(maxexp, MAXEXP), 1); expmin = -expmax - 1; return result; } int float_setprecision( int digits) { int result; result = maxdigits; maxdigits = _max(_min(digits, MAXDIGITS), 1); return result; } /* checking the limits on exponents */ char float_isvalidexp( int exp) { return exp >= expmin && exp <= expmax; } /* clears the error state as well */ Error float_geterror() { Error tmp; tmp = float_error; float_error = Success; return tmp; } /* the first error blocks all others as it may be the source of a cascade of dependent errors */ void float_seterror( Error code) { if (float_error == Success) float_error = code; } void floatnum_init() { bc_init_numbers(); float_geterror(); } void float_create( floatnum f) { f->significand = NULL; f->exponent = EXPNAN; #ifdef FLOATDEBUG memcpy(f->value, "NaN", 4); #endif } void float_setnan ( floatnum f) { bc_free_num(&(f->significand)); float_create(f); } char _setnan( floatnum result) { float_setnan(result); return FALSE; } char _seterror( floatnum result, Error code) { float_seterror(code); return _setnan(result); } void float_setzero ( floatnum f) { bc_free_num(&(f->significand)); f->exponent = EXPZERO; #ifdef FLOATDEBUG f->value[0] ='0'; f->value[1] = 0; #endif } char _setzero( floatnum result) { float_setzero(result); return TRUE; } char float_isnan( cfloatnum f) { return _is_special(f) && f->exponent != EXPZERO; } char float_iszero( cfloatnum f) { return _is_special(f) && f->exponent == EXPZERO; } int float_getlength( cfloatnum f) { return _is_special(f)? 0 : _scaleof(f) + 1; } char float_getdigit( cfloatnum f, int ofs) { if (ofs >= float_getlength(f) || ofs < 0) return 0; return _digit(f, ofs); } /* checks whether f is a NaN and sets the float_error variable accordingly. Used in parameter checks when float_xxx calls are executed. FALSE is returned if a NaN is encountered. */ char _checknan( cfloatnum f) { if (!float_isnan(f)) return TRUE; float_seterror(NoOperand); return FALSE; } /* checks whether is positive and sets the float_error variable accordingly. Used in parameter checks when float_xxx calls are executed. Some operations accept a special value like EXACT, that has to pass this check, even though its numerical encoding violates the boundaries. If a function does not accept a special value, use NOSPECIALVALUE as a parameter for . TRUE is returned if the check is passed. The check for the limit MAXDIGITS is not executed here, because some intermediate operations have to succeed on more than MAXDIGITS digits */ static char _checkdigits( int digits, int specialval) { if ((digits > 0 && digits <= maxdigits) || digits == specialval) return TRUE; float_seterror(InvalidPrecision); return FALSE; } /* backward-scans the significand in . Returns the number of digits equal to beginning with the +1-th digit of f->significand->n_value. */ static int _bscandigit( cfloatnum f, int scale, char digit) { char* p; char* ps; ps = _valueof(f); for (p = ps + scale + 1; p-- != ps && *p == digit;); return scale - (p - ps); } /* scans two significands for the first occurrence of a pair of different digits. Returns the number of equal digits at the beginning */ static int _scan_equal( floatnum v1, floatnum v2) { int count, i; char* p1; char* p2; count = _min(_scaleof(v1), _scaleof(v2)); p1 = _valueof(v1); p2 = _valueof(v2); i = 0; for (; *(p1++) == *(p2++) && ++i <= count;); return i; } /* scans two significands until it finds a digit different from 0 in the first significand, or a digit different from 9 in the second operand. The scan is limited by compares and starts with the *second* digit in the significands. Returns the number of found (0,9) pairs. */ static int _scan_09pairs( floatnum f1, floatnum f2, int count) { char* p; char* p1; char* p2; p1 = _valueof(f1) + 1; p2 = _valueof(f2) + 1; p = p1; for (; count-- > 0 && *p1 == 0 && *(p2++) == 9; ++p1); return p1 - p; } signed char float_getsign( cfloatnum f) { if(_is_special(f)) return 0; return f->significand->n_sign == PLUS? 1 : -1; } void float_setsign( floatnum f, signed char s) { if (s == 1 || s == -1) { if(!_is_special(f)) _setsign(f, s); } else if (s != 0) float_setnan(f); } char float_neg( floatnum f) { float_setsign(f, -float_getsign(f)); return _checknan(f); } char float_abs( floatnum f) { if(float_getsign(f) == -1) float_neg(f); return _checknan(f); } signed char float_cmp( cfloatnum val1, cfloatnum val2) { signed char sgn1; if (!_checknan(val1) || !_checknan(val2)) return UNORDERED; sgn1 = float_getsign(val1); if (float_getsign(val2) != sgn1) { if (sgn1 != 0) return sgn1; return -float_getsign(val2); } if (val1->exponent > val2->exponent) return sgn1; if (val1->exponent < val2->exponent) return -sgn1; if (_is_special(val1)) return 0; return (bc_compare(val1->significand, val2->significand)); } /* normalizing process: hides leading zeros in a significand and corrects the exponent accordingly */ static void _corr_lead_zero( floatnum f) { int count; count = _scan_digit(_valueof(f), float_getlength(f), 0); _hidefirst(f, count); f->exponent-=count; } /* normalizing process: if the significand is > 10 in magnitude, this function corrects this */ static void _corr_overflow( floatnum f) { int shift; shift = _lenof(f) - 1; _movepoint(f, -shift); f->exponent += shift; } /* cuts off trailing zeros at the end of a significand */ static void _corr_trailing_zeros( floatnum f) { _hidelast(f, _bscandigit(f, _scaleof(f), 0)); } static char hexdigits[] = "0123456789ABCDEF"; int float_getsignificand( char* buf, int bufsz, cfloatnum f) { int idx, lg; if (bufsz <= 0) return 0; if (float_isnan(f)) { *buf = 'N'; return 1; } if (float_iszero(f)) { *buf = '0'; return 1; } idx = -1; lg = _min(bufsz, float_getlength(f)); for(; ++idx < lg;) *(buf++) = hexdigits[(int)float_getdigit(f, idx)]; return lg; } int float_getexponent( cfloatnum f) { if (_is_special(f)) return 0; return f->exponent; } int float_getscientific( char* buf, int bufsz, cfloatnum f) { char b[42]; /* supports exponents encoded in up to 128 bits */ int sgnlg, explg, mlg; /* handle special cases */ if(float_isnan(f)) { if (bufsz < 4) return -1; memcpy(buf, "NaN\0", 4); return 3; } if(float_iszero(f)) { if (bufsz < 2) return -1; *buf = '0'; *(buf+1) = '\0'; return 1; } /* set one byte aside for sign? */ sgnlg = 0; if(float_getsign(f) < 0) sgnlg = 1; /* convert the exponent */ sprintf(b, "%d", float_getexponent(f)); explg = strlen(b); /* 3 extra bytes for dot, exp char and terminating \0 */ bufsz -= explg + sgnlg + 3; /* rest is for significand */ if (bufsz <= 0) /* buffer too small */ return-1; if(sgnlg > 0) *(buf++) = '-'; /* get the digit sequence of the significand, trailing zeros cut off */ mlg = float_getsignificand(++buf, bufsz, f) - 1; /* move the first digit one byte to the front and fill the gap with a dot */ *(buf-1) = *buf; *(buf++) = '.'; /* append the exponent */ *(buf+mlg) = 'e'; memcpy(buf+mlg+1, b, explg); /* the trailing \0 */ *(buf+mlg+explg+1) = '\0'; return sgnlg + mlg + explg + 3; } #ifdef FLOATDEBUG void _setvalue_(floatnum f) { f->value[float_getsignificand(f->value+2, sizeof(f->value)-3, f)+2] = 0; f->value[1] = f->value[2]; f->value[2] = '.'; f->value[0] = float_getsign(f) < 0? '-' : '+'; } #endif int float_setsignificand( floatnum f, int* leadingzeros, const char* buf, int bufsz) { const char* p; const char* dot; const char* last; const char* b; char* bcp; int zeros; int lg; char c; float_setnan(f); if (bufsz == NULLTERMINATED) bufsz = strlen(buf); /* initialize the output parameters for all early out branches */ if (leadingzeros != NULL) *leadingzeros = 0; if (bufsz <= 0) return -1; dot = memchr(buf, '.', bufsz); /* do not accept more than 1 dots */ if (dot != NULL && memchr(dot + 1, '.', bufsz - (dot - buf)) != NULL) return -1; last = buf + bufsz; /* points behind the input buffer */ /* skip all leading zeros */ b = _memskip(buf, last, '0'); /* is the first non-zero character found a dot? */ if (b == dot) /* then skip all zeros following the dot */ b = _memskip(b+1, last, '0'); /* the 'leading zeros' */ zeros = b - buf - (dot == NULL || dot >= b? 0:1); /* only zeros found? */ if (b == last) { /* indicate no dot, no leading zeros, because this does not matter in case of zero */ if (bufsz > (dot == NULL? 0:1)) float_setzero(f); /* do not accept a dot without any zero */ return -1; } /* size of the rest buffer without leading zeros */ bufsz -= b - buf; /* does the rest buffer contain a dot? */ lg = dot >= b && dot - b < maxdigits? 1 : 0; /* points behind the last significant digit */ p = b + _min(maxdigits + lg, bufsz); /* digits, limited by MAXDIGITS */ lg = _min(maxdigits, bufsz - lg); /* reduce lg by the number of trailing zeros */ for (; *--p == '0'; --lg); if (*(p--) == '.') for (; *(p--) == '0'; --lg); /* get a bc_num of sufficient size */ f->significand = bc_new_num(1, lg - 1); if (f->significand == NULL) return -1; /* exponent is forced to 0 */ f->exponent = 0; /* copy lg digits into bc_num buffer, scan the rest for invalid characters */ bcp = _valueof(f); for(; --bufsz >= 0;) { c = *(b++); if (c != '.') /* ignore a dot */ { if (c < '0' || c > '9') { /* invalid character */ float_setnan(f); return -1; } if (--lg >= 0) *(bcp++) = c - '0'; } } if (leadingzeros != NULL) *leadingzeros = zeros; #ifdef FLOATDEBUG _setvalue_(f); #endif return dot == NULL? -1 : dot - buf; } void float_setexponent( floatnum f, int exponent) { if (!_is_special(f)) { if (!float_isvalidexp(exponent)) float_setnan(f); else f->exponent = exponent; } } void float_setscientific( floatnum f, const char* buf, int bufsz) { int exppos; int zeros; int dotpos; unsigned exp, ovfl; signed char expsign, msign; const char* expptr; const char* last; char c; float_setnan(f); if (bufsz == NULLTERMINATED) bufsz = strlen(buf); /* find the offset of the exponent character, or -1, if not found */ for(exppos = bufsz; --exppos >= 0;) if ((c = *(buf+exppos)) == 'E' || c == 'e') break; /* marks the end of the exponent string */ last = buf + bufsz; /* pre-set exponent to +0, which is the right value, if there is no exponent. */ exp = 0; expsign = 1; ovfl = 0; if (exppos >= 0) { /* points behind the exponent character */ expptr = buf + (exppos + 1); if (expptr == last) /* do not accept an exponent char without an integer */ return; /* get the exponent sign */ switch(*expptr) { case '-': expsign = -1; /* and fall through */ case '+': ++expptr; } if (expptr == last) /* do not accept a sign without a digit following */ return; /* encode the sequence of digits into an unsignedeger */ for (;expptr != last ;) { if (*expptr < '0' || *expptr > '9') /* invalid char encountered */ return; ovfl = 10; if (_longmul(&exp, &ovfl)) { ovfl = *(expptr++) - '0'; _longadd(&exp, &ovfl); } if (ovfl != 0 || exp > EXPMAX+1) { /* do not return immediately, because the significand can be zero */ ovfl = 1; break; } } /* move the last pointer to the exponent char.*/ last = buf + exppos; } /* last points behind the significand part. exp is at most -EXPMIN */ /* get the sign of the significand */ msign = 1; if (buf != last) switch(*buf) { case '-': msign = -1; /* fall through */ case '+': ++buf; } /* let setsignificand convert the sequence of digits into a significand. If a dot is found, its position is given in dotpos, -1 otherwise. zeros are the count of leading '0' digits before the first non_zero digit. */ dotpos = float_setsignificand(f, &zeros, buf, last-buf); if (_is_special(f)) /* setsignificand either found a zero or encountered invalid characters */ return; /* if we did not find a dot, we assume an integer, and put the dot after last digit */ if (dotpos == -1) dotpos = last - buf; /* leading zeros shift the dot to the left. dotpos is now the exponent that results from the position of the dot in the significand. */ dotpos -= zeros+1; /* combine the dot position with the explicit exponent */ if (ovfl != 0 || !_checkadd(&dotpos, expsign * (int)exp)) /* exponent overflow */ float_setnan(f); float_setexponent(f, dotpos); float_setsign(f, msign); } /* normalizes a significand such that 1 <= x < 10. If the exponent overflows during this operation this is notified. */ static char _normalize( floatnum f) { _corr_lead_zero(f); if (f->significand != NULL && _lenof(f) > 1) _corr_overflow(f); if (f->significand != NULL) _corr_trailing_zeros(f); if (f->significand != NULL && !float_isvalidexp(f->exponent)) { float_seterror(Underflow); if (f->exponent > 0) float_seterror(Overflow); float_setnan(f); } #ifdef FLOATDEBUG if (f->significand != NULL) _setvalue_(f); #endif return f->significand != NULL; } void float_setinteger(floatnum dest, int value) { char buf[BITS_IN_UNSIGNED/3 + 3]; sprintf(buf, "%d", value); float_setscientific(dest, buf, NULLTERMINATED); } void float_move( floatnum dest, floatnum source) { if (dest != source) { float_setnan(dest); *dest = *source; float_create(source); } } /* creates a copy of and assigns it to . The significand is guaranteed to have +1 digits. The significand is truncated, or padded with zeros to the right, to achieve the desired length. may assume the special value EXACT, in which case a true copy is generated. This function allows an in-place copy (dest == source). */ static void _scaled_clone( floatnum dest, cfloatnum source, int scale) { /* dest == source allowed! */ bc_num mant; unsigned exp; signed char sign; mant = NULL; if(scale == EXACT) scale = _scaleof(source); if (dest == source && scale <= _scaleof(source)) { _setscale(dest, scale); return; } mant = bc_new_num(1, scale); scale = _min(scale, _scaleof(source)); memcpy(mant->n_value, _valueof(source), scale+1); sign = float_getsign(source); exp = source->exponent; float_setnan(dest); dest->exponent = exp; dest->significand = mant; #ifdef FLOATDEBUG _setvalue_(dest); #endif float_setsign(dest, sign); } char float_copy( floatnum dest, cfloatnum source, int digits) { int scale, save; if (digits == EXACT) digits = _max(1, float_getlength(source)); if (!_checkdigits(digits, NOSPECIALVALUE)) return _seterror(dest, InvalidPrecision); if (_is_special(source)) { if (dest != source) float_free(dest); *dest = *source; } else { // invariant: source has to be restored, if it is != dest scale = _min(digits - 1, _scaleof(source)); save = _limit_scale((floatnum)source, scale); _corr_trailing_zeros((floatnum)source); _scaled_clone(dest, source, EXACT); if (dest != source) _setscale(source, save); } return TRUE; } /* rounding a value towards zero */ static void _trunc( floatnum dest, cfloatnum x, int scale) { scale -= _bscandigit(x, scale, 0); _scaled_clone(dest, x, scale); #ifdef FLOATDEBUG _setvalue_(dest); #endif } /* rounding a value towards infinity */ static char _roundup( floatnum dest, cfloatnum x, int scale) { scale -= _bscandigit(x, scale, 9); _scaled_clone(dest, x, _max(0, scale)); if (scale < 0) { *_valueof(dest) = 1; if (!float_isvalidexp(++dest->exponent)) return FALSE; } else { ++*(_valueof(dest) + scale); } #ifdef FLOATDEBUG _setvalue_(dest); #endif return TRUE; } char float_round( floatnum dest, cfloatnum src, int digits, roundmode mode) { int scalediff, scale; char digit; signed char sign, updown; if (mode > TOMINUSINFINITY) return _seterror(dest, InvalidParam); if (!_checkdigits(digits, NOSPECIALVALUE)) return _setnan(dest); if (float_isnan(src)) return _seterror(dest, NoOperand); updown = 0; scale = digits - 1; if (float_getlength(src) > digits) { sign = float_getsign(src); switch(mode) { case TONEAREST: scalediff = _scaleof(src) - scale; if (scalediff > 0) { digit = _digit(src, digits); if (digit < 5 || (digit == 5 && scalediff == 1 && (_digit(src, scale) & 1) == 0)) updown = -1; else updown = 1; } break; case TOZERO: updown = -1; break; case TOINFINITY: updown = 1; break; case TOPLUSINFINITY: updown = sign; break; case TOMINUSINFINITY: updown = -sign; break; } } switch (updown) { case 1: if (!_roundup(dest, src, scale)) return _seterror(dest, Overflow); break; case 0: float_copy(dest, src, digits); break; case -1: _trunc(dest, src, scale); break; } return TRUE; } char float_int( floatnum f) { if (!_checknan(f)) return FALSE; if (f->exponent < 0) float_setzero(f); else if (!float_iszero(f)) float_round(f, f, f->exponent+1, TOZERO); return TRUE; } char float_frac( floatnum f) { if (!_checknan(f) || float_iszero(f) || f->exponent < 0) return !float_isnan(f); if (_scaleof(f) <= f->exponent) float_setzero(f); else { int leadingzeros = 0; _hidefirst(f, f->exponent + 1); leadingzeros = _scan_digit(_valueof(f), float_getlength(f), 0); _hidefirst(f, leadingzeros); f->exponent = -leadingzeros - 1; #ifdef FLOATDEBUG _setvalue_(f); #endif } return TRUE; } /* the general purpose add/subtract routine that deals with the ordinary case. */ static char _addsub_normal( floatnum dest, floatnum summand1, floatnum summand2, int digits) { floatstruct tmp; int expdiff; int scale; int fulllength; int extradigit; /* the operands are ordered by their exponent */ expdiff = (unsigned)(summand1->exponent - summand2->exponent); /* the full length of the sum (without carry) */ fulllength = _max(expdiff + _scaleof(summand2), _scaleof(summand1)) + 1; extradigit = 0; if (digits == EXACT || digits > fulllength) digits = fulllength; else { if (float_getsign(summand1) + float_getsign(summand2) == 0) extradigit = 1; /* a true subtraction needs no space for a carry */ if (expdiff > digits + extradigit) /* second operand underflows due to exponent diff */ return float_copy(dest, summand1, digits+extradigit); } if (digits > maxdigits) return _seterror(dest, InvalidPrecision); /* we cannot add the operands directly because of possibly different exponents. So we assume the second operand "to be OK" and shift the decimal point of the first appropriately to the right. There is a cheap way to do this: increment len by expdiff and decrement scale by the same amount. But: Check the operand is long enough to do this. */ float_create(&tmp); if (_scaleof(summand1) < expdiff) { _scaled_clone(&tmp, summand1, expdiff); summand1 = &tmp; } scale = digits + extradigit - (int)expdiff - 1; _movepoint(summand1, expdiff); /* truncate overly long operands */ _limit_scale(summand1, scale); _limit_scale(summand2, scale); /* add */ dest->exponent = summand2->exponent; bc_add(summand1->significand, summand2->significand, &(dest->significand), scale); float_free(&tmp); return _normalize(dest); } static char _sub_checkborrow( floatnum dest, floatnum summand1, floatnum summand2, int digits) { /* the operands have opposite signs, the same exponent, but their first digit of the significand differ. The operands are ordered by this digit. */ int result; int borrow; int scale1, scale2; char save; char* v1; char* v2; /* Cancellation occurs, when the operands are of type p.000...yyy - q.999...xxx, p-q == 1, because a borrow propagates from the difference ..0yyy.. - ..9xxx.., leaving zeros in the first part. We check for this here. */ borrow = 0; if (_digit(summand1, 0) - _digit(summand2, 0) == 1) { scale1 = _scaleof(summand1); scale2 = _scaleof(summand2); if (scale1 == 0) /* the special case of a one-digit first operand p. - q.999..xxx */ borrow = _scan_digit(_valueof(summand2) + 1, scale2, 9); else if (scale2 > 0) /* count the 0 - 9 pairs after the first digit, the area where a borrow can propagate */ borrow = _scan_09pairs(summand1, summand2, _min(scale1, scale2)); /* In case of a one-digit second operand (p.yyy.. - q. == 1.yyy..), nothing is cancelled out. Borrow is already set to 0, and this is the correct value for this case, so nothing has to be done here */ if (borrow > 0) { /* we have cancellation here. We skip all digits, that cancel out due to a propagating borrow. These include the first digit and all following (0,9) digit pairs, except the last one. The last pair may be subject to cancellation or not, we do not care, because the following digit pair either yields a non-zero difference, or creates no borrow. Our standard adder is good enough to deal with such a limited cancelling effect. We will replace the last (0,9) digit pair with a (9,8) pair. This prevents the creation of a borrow, and yet, will yield the correct result */ /* hide all digits until the last found 0 - 9 pair */ summand2->exponent -= borrow; summand1->exponent -= borrow; /* in case of a one-digit significand, there is nothing to hide */ if (scale1 > 0) _hidefirst(summand1, borrow); _hidefirst(summand2, borrow); /* we replace the last found 0 - 9 pair by a 9 - 8 pair, avoiding a carry, yet yielding the correct result */ save = *(v1 = _valueof(summand1)); *v1 = 9; *(v2 = _valueof(summand2)) = 8; } } result = _addsub_normal(dest, summand1, summand2, digits); /* restore the modified digits */ if (borrow > 0) { if (summand1 != dest) *v1 = save; if (summand2 != dest) *v2 = 9; } return result; } static char _sub_expdiff0( floatnum dest, floatnum summand1, floatnum summand2, int digits) { int eq; int result; /* the operands are ordered by their significand length, and have the same exponent, and different sign */ /* One type of cancellation is when both significands set out with the same digits. Since these digits cancel out during subtraction, we look out for the first pair of different digits. eq receives the number of equal digits, which may be 0 */ eq = _scan_equal(summand1, summand2); if (float_getlength(summand2) == eq) { /* the complete second operand is cancelled out */ if (float_getlength(summand1) == eq) /* op1 == -op2 */ return _setzero(dest); /* If xxx.. denotes the second operand, the (longer) first one is of form xxx..yyy.., since it has the same digits in the beginning. During subtraction the xxx... part is cancelled out, and this leaves yyy... as the subtraction result. By copying the yyy... to the result, we can shortcut the subtraction. But before doing so, we have to check yyy... for leading zeros, because the cancellation continues in this case. */ eq += _scan_digit(_valueof(summand1) + eq, float_getlength(summand1) - eq, 0); _hidefirst(summand1, eq); result = float_copy(dest, summand1, digits); dest->exponent -= eq; return result != 0 && _normalize(dest); } /* hide the identical digits, and do the subtraction without them. */ summand1->exponent -= eq; summand2->exponent -= eq; _hidefirst(summand1, eq); _hidefirst(summand2, eq); /* order the operands by their first digit */ if (_digit(summand1, 0) >= _digit(summand2, 0)) return _sub_checkborrow(dest, summand1, summand2, digits); return _sub_checkborrow(dest, summand2, summand1, digits); } static char _sub_expdiff1( floatnum dest, floatnum summand1, floatnum summand2, int digits) { /* Cancellation occurs when subtracting 0.9xxx from 1.0yyy */ int result; char singledigit; char* v1; char* v2; /* the operands have different sign, are ordered by their exponent, and the difference of the exponents is 1 */ /* 1.0yyy may be given as a single digit 1 or as a string of digits starting with 1.0 */ singledigit = _scaleof(summand1) == 0; if (_digit(summand1, 0) != 1 || _digit(summand2, 0) != 9 || (!singledigit && _digit(summand1, 1) != 0)) return _addsub_normal(dest, summand1, summand2, digits); /* we have cancellation here. We transform this case into that of equal exponents. */ /* we align both operands by hiding the first digit (1) of the greater operand. This leaves .0yyy which matches the second operand .9xxx. Unfortunately, if the first operand has only one digit, we cannot hide it, so we have to work around this then. */ if (!singledigit) _hidefirst(summand1, 1); /* we change the leading digits into a '9' and a '8' resp. So we finally subtract .8xxx from .9yyy, yielding the correct result. */ v1 = _valueof(summand1); v2 = _valueof(summand2); *v1 = 9; *v2 = 8; summand1->exponent--; result = _sub_checkborrow(dest, summand1, summand2, digits); /* restore the original digits */ if (summand1 != dest) *v1 = singledigit? 1 : 0; if (summand2 != dest) *v2 = 9; return result; } static char _sub_ordered( floatnum dest, floatnum summand1, floatnum summand2, int digits) { /* we have to check for cancellation when subtracting. Cancellation occurs when the operands are almost equal in magnitude. E.g. in 1.234 - 1.226 = 0.008, the result is on quite a different scale than the operands. Actually, this is a big problem, because it means that the (true) subtraction is numerically not stable. There is no way to get around this; you always have to take this into account, when subtracting. We make the best out of it, and check for cancellation in advance, so the result is at least valid to all digits, if the operands are known to be exact. Cancellation occurs only, if the difference between the exponents is 1 at most. We prepare the critical cases in specialized routines, and let the standard routine do the rest. */ /* the operands are ordered by their exponent */ unsigned expdiff; expdiff = (unsigned)(summand1->exponent - summand2->exponent); switch (expdiff) { case 0: /* order the operands by their length of the significands */ if (float_getlength(summand1) >= float_getlength(summand2)) return _sub_expdiff0(dest, summand1, summand2, digits); return _sub_expdiff0(dest, summand2, summand1, digits); case 1: return _sub_expdiff1(dest, summand1, summand2, digits); } return _addsub_normal(dest, summand1, summand2, digits); } static char _addsub_ordered( floatnum dest, floatnum summand1, floatnum summand2, int digits) { /* operands are ordered by their exponent */ /* handle a bunch of special cases */ if (!_checkdigits(digits, EXACT) || !_checknan(summand1)) return _setnan(dest); if (float_iszero(summand2)) return float_copy(dest, summand1, digits); /* separate true addition from true subtraction */ if (float_getsign(summand1) == float_getsign(summand2)) return _addsub_normal(dest, summand1, summand2, digits); return _sub_ordered(dest, summand1, summand2, digits); } char float_add( floatnum dest, cfloatnum summand1, cfloatnum summand2, int digits) { bc_struct bc1, bc2; floatstruct tmp1, tmp2; floatnum s1, s2; /* the adder may occasionally adjust operands to his needs. Hence we work on temporary structures */ s1 = dest; s2 = dest; if (dest != summand1) { _copyfn(&tmp1, summand1, &bc1); s1 = &tmp1; } if (dest != summand2) { _copyfn(&tmp2, summand2, &bc2); s2 = &tmp2; } /* order the operands by their exponent. This should bring a NaN always to the front, and keeps zeros after any other number. */ if (s1->exponent >= s2->exponent) return _addsub_ordered(dest, s1, s2, digits); return _addsub_ordered(dest, s2, s1, digits); } char float_sub( floatnum dest, cfloatnum minuend, cfloatnum subtrahend, int scale) { int result; if (minuend == subtrahend) { /* changing the sign of one operand would change that of the other as well. So this is a special case */ if(!_checknan(minuend)) return FALSE; _setzero(dest); } /* do not use float_neg, because it may change float_error */ float_setsign((floatnum)subtrahend, -float_getsign(subtrahend)); result = float_add(dest, minuend, subtrahend, scale); if (dest != subtrahend) float_setsign((floatnum)subtrahend, -float_getsign(subtrahend)); return result; } char float_mul( floatnum dest, cfloatnum factor1, cfloatnum factor2, int digits) { int result; int fullscale; int savescale1, savescale2; int scale; /* handle a bunch of special cases */ if (!_checkdigits(digits, EXACT) || !_checknan(factor1) || !_checknan(factor2)) /* invalid scale value or NaN operand */ return _setnan(dest); if (float_iszero(factor1) || float_iszero(factor2)) return _setzero(dest); scale = digits - 1; fullscale = _scaleof(factor1) + _scaleof(factor2); if (digits == EXACT || scale > fullscale) scale = fullscale; if (scale >= maxdigits) /* scale too large */ return _seterror(dest, InvalidPrecision); /* limit the scale of the operands to sane sizes */ savescale1 = _limit_scale((floatnum)factor1, scale); savescale2 = _limit_scale((floatnum)factor2, scale); /* multiply */ dest->exponent = factor1->exponent + factor2->exponent; bc_multiply(factor1->significand, factor2->significand, &(dest->significand), scale); result = _normalize(dest); /* reverse order is necessary in case factor1 == factor2 */ if (dest != factor2) _setscale(factor2, savescale2); if (dest != factor1) _setscale(factor1, savescale1); return result; } char float_div( floatnum dest, cfloatnum dividend, cfloatnum divisor, int digits) { int result; int savescale1, savescale2; int exp; /* handle a bunch of special cases */ if (!_checkdigits(digits, INTQUOT) || !_checknan(dividend) || !_checknan(divisor)) return _setnan(dest); if (float_iszero(divisor)) return _seterror(dest, ZeroDivide); if (float_iszero(dividend)) /* 0/x == 0 */ return _setzero(dest); exp = dividend->exponent - divisor->exponent; /* check for integer quotient */ if(digits == INTQUOT) { if (exp < 0) return _setzero(dest); digits = exp; } /* scale OK? */ if(digits > maxdigits) return _seterror(dest, InvalidPrecision); /* limit the scale of the operands to sane sizes */ savescale1 = _limit_scale((floatnum)dividend, digits); savescale2 = _limit_scale((floatnum)divisor, digits); /* divide */ result = TRUE; dest->exponent = exp; bc_divide(dividend->significand, divisor->significand, &(dest->significand), digits); if (bc_is_zero(dest->significand)) float_setzero(dest); else result = _normalize(dest); /* reverse order is necessary in case divisor == dividend */ if (dest != divisor) _setscale(divisor, savescale2); if (dest != dividend) _setscale(dividend, savescale1); return result; } char float_divmod( floatnum quotient, floatnum remainder, cfloatnum dividend, cfloatnum divisor, int digits) { int exp, exp1; if (!_checkdigits(digits, INTQUOT) || !_checknan(dividend) || !_checknan(divisor) || quotient == remainder || float_iszero(divisor) || float_getlength(divisor) > maxdigits) { if (quotient == remainder) float_seterror(InvalidParam); if (float_getlength(divisor) > maxdigits) float_seterror(TooExpensive); if (float_iszero(divisor)) float_seterror(ZeroDivide); float_setnan(quotient); return _setnan(remainder); } if (float_iszero(dividend)) { float_setzero(quotient); return _setzero(remainder); } exp1 = dividend->exponent; exp = exp1 - divisor->exponent; if(digits-- == INTQUOT) { if (exp < 0) { if (float_copy(remainder, dividend, EXACT)) return _setzero(quotient); return _setnan(quotient); } digits = exp; } if (digits > maxdigits) { float_setnan(quotient); return _seterror(remainder, TooExpensive); } /* divide */ quotient->exponent = exp; remainder->exponent = exp1; bc_divmod(dividend->significand, divisor->significand, &(quotient->significand), &(remainder->significand), digits); /* if something goes wrong (one of the results overflows or underflows), always set both quotient and remainder to NaN */ if (bc_is_zero(remainder->significand)) float_setzero(remainder); else if (!_normalize(remainder)) return _setnan(quotient); if (bc_is_zero(quotient->significand)) float_setzero(quotient); else if (!_normalize(quotient)) return _setnan(remainder); return TRUE; } char float_sqrt(floatnum value, int digits) { if (!_checkdigits(digits, NOSPECIALVALUE) || !_checknan(value)) return _setnan(value); switch (float_getsign(value)) { case -1: return _seterror(value, OutOfDomain); case 0: return TRUE; } if ((value->exponent & 1) != 0) { if (float_getlength(value) == 1) _scaled_clone(value, value, 1); _movepoint(value, 1); } bc_sqrt(&value->significand, digits - 1); #ifdef FLOATDEBUG _setvalue_(value); #endif if (value->exponent >= 0) value->exponent >>= 1; else value->exponent = -((1-value->exponent) >> 1); return TRUE; } deepin-calculator-1.0.2/math/floatnum.h000066400000000000000000000437231325241207700200500ustar00rootroot00000000000000/* floatnum.h: Arbitrary precision floating point numbers header file. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATNUM_H # define FLOATNUM_H #include "number.h" #include "floatconfig.h" #include "floatio.h" #define NULLTERMINATED (-20) #define UNORDERED (-2) #define EXACT (-101) #define INTQUOT (-102) #define float_free(f) float_setnan(f) #ifdef __cplusplus extern "C" { #endif extern int maxdigits; typedef struct { bc_num significand; int exponent; #ifdef FLOATDEBUG char value[110]; #endif /* FLOATDEBUG */ } floatstruct; typedef floatstruct* floatnum; typedef const floatstruct* cfloatnum; typedef enum {TONEAREST, TOZERO, TOINFINITY, TOPLUSINFINITY, TOMINUSINFINITY} roundmode; /* initializes this module. Has to be called prior to the first use of any of the following functions */ void floatnum_init(); /* sets the error to `code' unless it is already set */ void float_seterror(Error code); /* gets the last error and clears the error afterwards */ Error float_geterror(); /* returns the current overflow limit. It is the maximum possible exponent. The smallest exponent is -`return value' - 1. This function never reports an error */ int float_getrange(); /* sets the overflow/underflow limit. Subsequent arithmetic results with exponents between `maxexp' >= exponent >= -`maxexp'-1 are considered valid, all others trigger overflow/underflow errors. `maxexp' cannot be greater than MAXEXP and not less than 1. Exceeding arguments are replaced by the respective limit. The return value is the old overflow limit. This function affects future results only. Current stored values are not subject to overflow/underflow checking, even when they are used as parameters to an operation. This function never reports an error */ int float_setrange(int maxexp); /* returns the current precision limit. Arithmetic results may be cut off after this number of decimal digits */ int float_getprecision(); /* sets the current maximum precision (in decimal digits) that is used by basic arithmetic operations. The precision is at least 1 and at most MAXDIGITS. An exceeding argument is replaced by the respective limit. Setting a new precision affects future operations only; currently set variables are kept unmodified. The return value is the old precision limit. This function never reports an error */ int float_setprecision(int digits); /* checks whether the submitted exponent is within the current overflow and underflow limits. This function never reports an error */ char float_isvalidexp(int exp); /* initializes a new floatnum to NaN. Call this before the first use of a floatnum variable. The destructing function is float_setnan or its alias, float_free. This function never reports an error. */ void float_create(floatnum f); /* finalizes a variable. To avoid memory leaks, call this before a floatnum is freed. A special value (NaN = not a number) is loaded into `f', so any subsequent arithmetic operation on this variable will fail. However, a variable such finalized can still be re-used without prior initialization, by making it the destination of an operation. If you wish to deliberately "empty" a variable, without detroying it, call this function. An alias "float_free" to this function is defined that you may use anywhere as a replacement for float_setnan. This function never reports an error. */ void float_setnan(floatnum f); /* returns the base 10 exponent of the value in `f'. If `f' is zero or NaN, the returned exponent is 0. This function never reports an error. */ int float_getexponent(cfloatnum f); /* fills the buffer `buf' of size `bufsz' with an ASCII string representing the significand of `f'. No zeros are padded to the right to fill the buffer in case of a short significand. If `bufsz' <= 0, the function returns immediately with result 0. If the significand does not fit completely into the buffer, the output is stopped when the last buffer byte is written to. A non-zero significand yields a sequence of digits, without a decimal point; zero yields "0" and NaN "N". On truncation, no trailing zeros are removed. Exponent and sign are ignored, and no decimal point is written. No '\0' character is appended to the right. The return value are the number of characters written to the buffer. This function never reports an error. */ int float_getsignificand(char* buf, int bufsz, cfloatnum f); /* returns the number of digits in the significand, or 0 for NaN and zero. This function never reports an error. */ int float_getlength(cfloatnum f); /* returns 1, if `f' is positive, -1, if `f' is negative, and 0 if `f' is zero or NaN. This function never reports an error. */ signed char float_getsign(cfloatnum f); /* writes the value stored in `f' as an ASCIIZ string into a buffer of size `bufsz'. If the buffer is too small to hold the full value, the significand is truncated appropriately. If the buffer is too small to even store the most significant digit of the significand besides exponent and sign, nothing is stored at all, and -1 is returned. Else, the length of the output, but without the trailing \0 character, is returned. The output format is the usual scientific format. On truncation, no trailing zeros are removed from the output of the significand. Examples of an output: value output ----- ------ NaN NaN\0 0 0\0 1 1.e0\0 1.2 1.2e0\0 0.5 5.e-1\0 -1 -1.e0\0 1.009 1.00e0\0 (truncated to 3 digits) 10^10 1.e10\0 This function does not touch the adjacent bytes of the final output. If no reasonable output is possible, the complete buffer is left unchanged, not even the final \0 character is written. This function never reports an error. */ int float_getscientific(char* buf, int bufsz, cfloatnum f); /* gets the `ofs'-th digit from the decimal representation of the significand of `f'. If `ofs' is negative or greater equal to the length of the significand, 0 is returned. The return value is between 0 and 9 (not the ASCII representation of these digits (0x30 - 0x39)). This function never returns an error */ char float_getdigit(cfloatnum f, int ofs); /* sets the significand according to the the ASCII text in buffer buf of size `bufsz'. The buffer must contain digits '0' -'9' only, with one possible exception: A single decimal point ('.') may be placed anywhere in the buffer. It is skipped while encoding the significand. The function searches the buffer for the first non-zero digit, and starts the encoding from there. `f' is set to NaN, if the buffer fails to fulfill the above conditions. If the resulting significand exceeds digits, it is truncated. The exponent of `f' is set to 0, so the result is always NaN, 0 or a number between 1 and 9.99... If you want to set both the significand and the exponent of f, set the significand first. If `leadingzeros' is not NULL, and the result in `f' is neither zero nor NaN, the number of leading (and skipped) zeros are stored here. In case of NaN or zero, this value is 0. All trailing zeros in the significand of `f' are removed. The result is the position of the decimal point in `buf', or -1 if either none was found, or if it is not relevant (NaN or 0.0). This function never reports an error. */ int float_setsignificand(floatnum f, int* leadingzeros, const char* buf, int bufsz); /* sets the base 10 exponent of f to exponent. The significand is only changed when this operation fails. Integers greater than EXPMAX or smaller than EXPMIN are not accepted as exponent and let the operation fail, setting `f' to NaN. You cannot change the exponent of 0 or NaN, this is ignored. If you want to set both the significand and the exponent of `f', set the significand first. This function never reports an error. */ void float_setexponent(floatnum f, int exponent); /* converts an ASCII string of length `bufsz' in `buf' to `f'. `bufsz' may assume the special value NULLTERMINATED, in which case the first found \0 character terminates the input. The input format is [+|-][digit...][.[digit...][(e|E)[+|-]digit...]] At least one digit of the significand has to be present. Any non-valid input is converted into a NaN. This function never reports an error. */ void float_setscientific(floatnum f, const char* buf, int bufsz); /* if `s' is 1 or -1, the sign of `f' is set accordingly. Has no effect, if `f' == NaN or zero, or `s' == 0. `f' is set to NaN, if |s| > 1. This function never reports an error. */ void float_setsign(floatnum f, signed char s); /* sets dest to the value in `value'. This function never reports an error. */ void float_setinteger(floatnum dest, int value); /* sets a variable to the numerical value zero. This function never reports an error. */ void float_setzero (floatnum f); /* returns 1, if f contains the special NaN value, 0 otherwise. This function never reports an error. */ char float_isnan(cfloatnum f); /* returns 1, if f contains the value zero, 0 otherwise. This function never reports an error. */ char float_iszero(cfloatnum f); /* copies source to dest, limiting the significand to at most `digits' digits. The parameter `digits' may assume the value EXACT, in which case a full copy is made. If source and dest coincide, float_copy tries to re-use the significand. This prevents unnecessary copying. If a copy has to be made, the allocated space is just big enough to hold the significand, so no memory is wasted. A return value of 0 indicates an error. errors: InvalidPrecision, if `digits', or the length of the copy, exceeds `maxdigits' */ char float_copy(floatnum dest, cfloatnum source, int digits); /* transfers the contents of source to dest. source is assigned NaN afterwards. In contrast to float_copy, float_move does not create a copy of the significand (which employs memory allocation and copying), but transfers simply the data from the source to the destination. This function has been designed to implement, for example, swapping of variables in a fast way. If dest == source, nothing happens. This function never reports an error */ void float_move(floatnum dest, floatnum source); /* changes the value of `f' to -`f'. Has no effect on zero or NaN. A return value of 0 indicates an error. errors: NaNOperand */ char float_neg(floatnum f); /* changes the sign of `f', if `f' is negative. Has no effect on a NaN. A return value of 0 indicates an error. errors: NaNOperand */ char float_abs(floatnum f); /* compares two values and returns +1 if val1 > val2, 0 if val1 == val2 and -1 if val1 < val2. This function is not intended to be used with NaN's. If you pass it as an argument, UNORDERED is returned to indicate an error. errors: NaNOperand */ signed char float_cmp(cfloatnum val1, cfloatnum val2); /* rounds `f' to `digits' digits according to the submitted mode. If `digits' <= 0 or mode is not recognized, `f' is changed into a NaN. The same holds should the rounding operation overflow. mode == TONEAREST: checks whether the first cut off digit is a '5' or greater. In this case, the absolute value of the significand is rounded up, otherwise rounded down. If the part cut off is a single digit '5', the significand is rounded such that its last digit is even. mode == TOZERO: cuts off all digits after the `digits'th digit. This mode never overflows. mode = TOINFINITY: rounds positive numbers up, negative numbers down (towards greater magnitude). mode == TOPLUSINFINITY: always rounds up. So, negative values are effectively truncated. mode == TOMINUSINFINITY: always rounds down. So, negative values usually increase in magnitude. A return value of 0 indicates an error. errors: NaNOperand InvalidParam InvalidPrecision Overflow */ char float_round(floatnum dest, cfloatnum src, int digits, roundmode mode); /* cuts off the fractional part of `f'. The result is always less or equal in magnitude to the passed argument. A NaN yields a NaN. A return value of 0 indicates an error. errors: NaNOperand */ char float_int(floatnum f); /* cuts off the integer part of `f'. If the result is not equal to 0, it has the same sign as the argument. NaN yields NaN. A return value of 0 indicates an error. errors: NaNOperand */ char float_frac(floatnum f); /* adds the values in `summand1' and `summand2' and stores the result in `dest'. `dest' may coincide with either summand (or even both). The result is evaluated to `digits' or `digits'+1 digits. If `digits' is EXACT, the sum is evaluated to full scale (if possible). NaN is returned, if - (at least) one operand is NaN; - the result overflows or underflows; - `digits' is invalid, or the resulting digits exceed `maxdigits'. A return value of 0 indicates an error. errors: NaNOperand InvalidPrecision Overflow Underflow */ char float_add(floatnum dest, cfloatnum summand1, cfloatnum summand2, int digits); /* subtracts `subtrahend' from `minuend' and stores the result in `dest'. `dest' may coincide with either operand (or even both). The result is evaluated to `digits' or `digits'+1 digits. If `digits' is EXACT, the difference is evaluated to full scale (if possible). NaN is returned, if - (at least) one operand is NaN; - the result overflows or underflows; - `digits' is invalid, or the resulting digits exceed `maxdigits'. A return value of 0 indicates an error. errors: NaNOperand InvalidPrecision Overflow Underflow */ char float_sub(floatnum dest, cfloatnum minuend, cfloatnum subtrahend, int digits); /* multiplies both factors and stores the result in `dest'. `dest' may coincide with either factor (or even both). The result is evaluated to `digits' or `digits'+1 digits, or, if `digits' == EXACT, to full scale (if possible). NaN is returned, if - (at least) one operand is NaN; - the result overflows or underflows; - `digits' is invalid, or the resulting scale exceeds `maxdigits'. A return value of 0 indicates an error. errors: NaNOperand InvalidPrecision Overflow Underflow */ char float_mul(floatnum dest, cfloatnum factor1, cfloatnum factor2, int digits); /* divides `dividend' by `divisor' and stores the result in `dest'. `dest' may coincide with either operand (or even both). The result is evaluated to `digits' or `digits'+1 digits, or, if `digits' == INTQUOT, to the size of the integer part of the quotient. EXACT is not allowed, even in cases where the dividend is divisible by the divisor. NaN is returned, if - (at least) one operand is NaN; - the result overflows or underflows; - the divisor is zero; - `digits' is invalid, or the effective scale exceeds `maxdigits'. A return value of 0 indicates an error. errors: NaNOperand InvalidPrecision Overflow Underflow ZeroDivide */ char float_div(floatnum dest, cfloatnum dividend, cfloatnum divisor, int digits); /* evaluates the quotient, using `digits' steps of the schoolbook division algorithm. The quotient, thus, has `digits' or `digits'-1 digits, and is always truncated towards zero. The remainder fulfills the equation: remainder = dividend - quotient * divisor. `digits' may assume the special value INTQUOT, in which case the integer part of the quotient is calculated. This function is an exact operation anyway, so EXACT is not allowed here. `digits' is subject to the `maxdigits' limit. `remainder' and `quotient' have to be different variables, but apart from this, there are no other restrictions on the passed variables. If this function fails, both result variables are set to NaN. A return value of 0 indicates an error. errors: NaNOperand InvalidParam InvalidPrecision TooExpensive Overflow Underflow ZeroDivide */ char float_divmod(floatnum quotient, floatnum remainder, cfloatnum dividend, cfloatnum divisor, int digits); /* computes the sqare root of `value' to `digits' or `digits'+1 digits. `digits' == EXACT is not allowed, even if the argument is a square. NaN is returned, if - the operand is NaN, - `digits' exceeds `maxdigits' - the operand is negative. A return value 0 indicates an error. errors: NaNOperand InvalidPrecision OutOfDomain */ char float_sqrt(floatnum value, int digits); /* a few convenience functions used everywhere */ char _setnan(floatnum result); char _seterror(floatnum result, Error code); char _checknan(cfloatnum f); char _setzero(floatnum x); #ifdef __cplusplus } #endif #endif /* FLOATNUM_H */ deepin-calculator-1.0.2/math/floatpower.c000066400000000000000000000034351325241207700203740ustar00rootroot00000000000000/* floatpower.c: power operation, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatpower.h" #include "floatipower.h" #include "floatcommon.h" #include "floatlog.h" #include "floatexp.h" char _raise( floatnum x, cfloatnum exponent, int digits) { int iexp; int extra; extra = float_getexponent(exponent); if (digits + extra > maxdigits) extra = maxdigits - digits; if (float_isinteger(exponent)) { iexp = leadingdigits(exponent, float_getexponent(exponent) + 1); if (float_iszero(exponent) || iexp != 0) return _raisei(x, iexp, digits+extra); } if (digits + extra > MATHPRECISION) extra = MATHPRECISION - digits; _ln(x, digits+extra); if (!float_mul(x, x, exponent, digits+extra)) return 0; return _exp(x, digits); } deepin-calculator-1.0.2/math/floatpower.h000066400000000000000000000024711325241207700204000ustar00rootroot00000000000000/* floatpower.h: power operation, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATPOWER_H # define FLOATPOWER_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif char _raise(floatnum x, cfloatnum exponent, int digits); #ifdef __cplusplus } #endif #endif /* FLOATPOWER_H */ deepin-calculator-1.0.2/math/floatseries.c000066400000000000000000000123561325241207700205340ustar00rootroot00000000000000/* floatseries.c: basic series, based on floatnum. */ /* Copyright (C) 2007 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floatseries.h" #include "floatconst.h" #include "floatcommon.h" #include "floatexp.h" /* Though all these serieses can be used with arguments |x| < 1 or even more, the computation time increases rapidly with x. Tests show, that for 100 digit results, it is best to limit x to |x| < 0.01..0.02, and use reduction formulas for greater x */ /* the Taylor series of arctan/arctanh x at x == 0. For small |x| < 0.01 this series converges very fast, yielding 4 or more digits of the result with every summand. The working precision is adjusted, so that the relative error for 100-digit arguments is around 5.0e-100. This means, the error is 1 in the 100-th place (or less) */ void arctanseries( floatnum x, int digits, char alternating) { int expx; int expsqrx; int pwrsz; int addsz; int i; floatstruct xsqr; floatstruct pwr; floatstruct smd; floatstruct sum; /* upper limit of log(x) and log(result) */ expx = float_getexponent(x)+1; /* the summands of the series from the second on are bounded by x^(2*i-1)/3. So the summation yields a result bounded by (x^3/(1-x*x))/3. For x < sqrt(1/3) approx.= 0.5, this is less than 0.5*x^3. We need to sum up only, if the first places of the result (roughly x) are touched. Ignoring the effect of a possile carry, this is only the case, if x*x >= 2*10^(-digits) > 10^(-digits) Example: for x = 9e-51, a 100-digits result covers the decimal places from 1e-51 to 1e-150. x^3/3 is roughly 3e-151, and so is the sum of the series. So we can ignore the sum, but we couldn't for x = 9e-50 */ if (float_iszero(x) || 2*expx < -digits) /* for very tiny arguments arctan/arctanh x is approx.== x */ return; float_create(&xsqr); float_create(&pwr); float_create(&smd); float_create(&sum); /* we adapt the working precision to the decreasing summands, saving time when multiplying. Unfortunately, there is no error bound given for the operations of bc_num. Tests show, that the last digit in an incomplete multiplication is usually not correct up to 5 ULP's. */ pwrsz = digits + 2*expx + 1; /* the precision of the addition must not decrease, of course */ addsz = pwrsz; i = 3; float_mul(&xsqr, x, x, pwrsz); float_setsign(&xsqr, alternating? -1 : 1); expsqrx = float_getexponent(&xsqr); float_copy(&pwr, x, pwrsz); float_setzero(&sum); for(; pwrsz > 0; ) { /* x^i */ float_mul(&pwr, &pwr, &xsqr, pwrsz+1); /* x^i/i */ float_divi(&smd, &pwr, i, pwrsz); /* The addition virtually does not introduce errors */ float_add(&sum, &sum, &smd, addsz); /* reduce the working precision according to the decreasing powers */ pwrsz = digits - expx + float_getexponent(&smd) + expsqrx + 3; i += 2; } /* add the first summand */ float_add(x, x, &sum, digits+1); float_free(&xsqr); float_free(&pwr); float_free(&smd); float_free(&sum); } /* series expansion of cos/cosh - 1 used for small x, |x| <= 0.01. The function returns 0, if an underflow occurs. The relative error seems to be less than 5e-100 for a 100-digit calculation with |x| < 0.01 */ char cosminus1series( floatnum x, int digits, char alternating) { floatstruct sum, smd; int expsqrx, pwrsz, addsz, i; expsqrx = 2 * float_getexponent(x); float_setexponent(x, 0); float_mul(x, x, x, digits+1); float_mul(x, x, &c1Div2, digits+1); float_setsign(x, alternating? -1 : 1); expsqrx += float_getexponent(x); if (float_iszero(x) || expsqrx < EXPMIN) { /* underflow */ float_setzero(x); return expsqrx == 0; } float_setexponent(x, expsqrx); pwrsz = digits + expsqrx + 2; if (pwrsz <= 0) /* for very small x, cos/cosh(x) - 1 = (-/+)0.5*x*x */ return 1; addsz = pwrsz; float_create(&sum); float_create(&smd); float_copy(&smd, x, pwrsz); float_setzero(&sum); i = 2; while (pwrsz > 0) { float_mul(&smd, &smd, x, pwrsz+1); float_divi(&smd, &smd, i*(2*i-1), pwrsz); float_add(&sum, &sum, &smd, addsz); ++i; pwrsz = digits + float_getexponent(&smd); } float_add(x, x, &sum, digits+1); float_free(&sum); float_free(&smd); return 1; } deepin-calculator-1.0.2/math/floatseries.h000066400000000000000000000032031325241207700205300ustar00rootroot00000000000000/* floatseries.h: header file for basic series, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATSERIES_H # define FLOATSERIES_H #include "floatnum.h" #define artanhnear0(x, digits) arctanseries(x, digits, 0) #define arctannear0(x, digits) arctanseries(x, digits, 1) #define coshminus1near0(x, digits) cosminus1series(x, digits, 0) #define cosminus1near0(x, digits) cosminus1series(x, digits, 1) #ifdef __cplusplus extern "C" { #endif void arctanseries(floatnum x, int digits, char alternating); char cosminus1series(floatnum x, int digits, char alternating); #ifdef __cplusplus } #endif #endif /* FLOATSERIES_H */ deepin-calculator-1.0.2/math/floattrig.c000066400000000000000000000215471325241207700202110ustar00rootroot00000000000000/* floattrig.c: trigonometry functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #include "floattrig.h" #include "floatseries.h" #include "floatconst.h" #include "floatcommon.h" /* evaluates arctan x for |x| <= 1 relative error for a 100 digit result is 6e-100 */ void _arctanlt1( floatnum x, int digits) { floatstruct tmp; int reductions; if (float_iszero(x)) return; float_create(&tmp); reductions = 0; while(float_getexponent(x) >= -2) { float_mul(&tmp, x, x, digits); float_add(&tmp, &tmp, &c1, digits+2); float_sqrt(&tmp, digits); float_add(&tmp, &tmp, &c1, digits+1); float_div(x, x, &tmp, digits); ++reductions; } arctannear0(x, digits); for (;reductions-- > 0;) float_add(x, x, x, digits+1); float_free(&tmp); } /* evaluates arctan x for all x. The result is in the range -pi/2 < result < pi/2 relative error for a 100 digit result is 9e-100 */ void _arctan( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1) > 0) { sgn = float_getsign(x); float_abs(x); float_reciprocal(x, digits); _arctanlt1(x, digits); float_sub(x, &cPiDiv2, x, digits+1); float_setsign(x, sgn); } else _arctanlt1(x, digits); } /* evaluates arccos(1+x) for -0.5 <= x <= 0 arccos(1+x) = arctan(sqrt(-x*(2+x))/(1+x)) the relative error of a 100 digit result is < 5e-100 */ void _arccosxplus1lt0_5( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_setsign(x, 1); float_sqrt(x, digits); float_sub(&tmp, &tmp, &c1, digits); float_div(x, x, &tmp, digits+1); _arctan(x, digits); float_free(&tmp); } /* evaluates arcsin x for -0.5 <= x <= 0.5 arcsin x = arctan(x/sqrt(1-x*x)) the relative error of a 100 digit result is < 5e-100 */ void _arcsinlt0_5( floatnum x, int digits) { floatstruct tmp; if (2*float_getexponent(x) < -digits) return; float_create(&tmp); float_mul(&tmp, x, x, digits); float_sub(&tmp, &c1, &tmp, digits); float_sqrt(&tmp, digits); float_div(x, x, &tmp, digits+1); _arctanlt1(x, digits); float_free(&tmp); } /* evaluates arccos x for -1 <= x <= 1. The result is in the range 0 <= result <= pi. The relative error for a 100 digit result is < 5e-100 */ void _arccos( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) > 0) { float_sub(x, x, &c1, digits+1); _arccosxplus1lt0_5(x, digits); } else { _arcsinlt0_5(x, digits); float_sub(x, &cPiDiv2, x, digits+1); } if (sgn < 0) float_sub(x, &cPi, x, digits+1); } /* evaluates arccos (1+x) for -2 <= x <= 0. The result is in the range 0 <= x <= pi */ void _arccosxplus1( floatnum x, int digits) { if (float_abscmp(x, &c1Div2) <= 0) _arccosxplus1lt0_5(x, digits); else { float_add(x, x, &c1, digits); _arccos(x, digits); } } /* evaluates arcsin x for -1 <= x <= 1. The result is in the range -pi/2 <= result <= pi/2 The relative error for a 100 digit result is < 8e-100 */ void _arcsin( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1Div2) <= 0) _arcsinlt0_5(x, digits); else { sgn = float_getsign(x); float_abs(x); _arccos(x, digits); float_sub(x, &cPiDiv2, x, digits); float_setsign(x, sgn); } } /* evaluates cos x - 1 for x < |pi/4| relative error for 100 digit results is < 5e-100 */ char _cosminus1ltPiDiv4( floatnum x, int digits) { floatstruct tmp; int reductions; if (float_iszero(x)) return 1; float_abs(x); reductions = 0; while(float_getexponent(x) >= -2) { float_mul(x, x, &c1Div2, digits+1); ++reductions; } if (!cosminus1near0(x, digits) && reductions == 0) return !float_iszero(x); float_create(&tmp); for(; reductions-- > 0;) { float_mul(&tmp, x, x, digits); float_add(x, x, x, digits+2); float_add(x, x, &tmp, digits+2); float_add(x, x, x, digits+2); } float_free(&tmp); return 1; } /* evaluate sin x for |x| <= pi/4, using |sin x| = sqrt((1-cos x)*(2 + cos x-1)) relative error for 100 digit results is < 6e-100*/ void _sinltPiDiv4( floatnum x, int digits) { floatstruct tmp; signed char sgn; if (2*float_getexponent(x)+2 < -digits) /* for small x: sin x approx.== x */ return; float_create(&tmp); sgn = float_getsign(x); _cosminus1ltPiDiv4(x, digits); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_abs(x); float_sqrt(x, digits); float_setsign(x, sgn); float_free(&tmp); } /* evaluates tan x for |x| <= pi/4. The relative error for a 100 digit result is < 6e-100 */ void _tanltPiDiv4( floatnum x, int digits) { floatstruct tmp; signed char sgn; if (2*float_getexponent(x)+2 < -digits) /* for small x: tan x approx.== x */ return; float_create(&tmp); sgn = float_getsign(x); _cosminus1ltPiDiv4(x, digits); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_abs(x); float_sqrt(x, digits); float_sub(&tmp, &tmp, &c1, digits); float_div(x, x, &tmp, digits+1); float_setsign(x, sgn); float_free(&tmp); } /* evaluates cos x for |x| <= pi */ void _cos( floatnum x, int digits) { signed char sgn; float_abs(x); sgn = 1; if (float_cmp(x, &cPiDiv2) > 0) { sgn = -1; float_sub(x, &cPi, x, digits+1); } if (float_cmp(x, &cPiDiv4) <= 0) { if (2*float_getexponent(x)+2 < - digits) float_setzero(x); else _cosminus1ltPiDiv4(x, digits); float_add(x, x, &c1, digits); } else { float_sub(x, &cPiDiv2, x, digits+1); _sinltPiDiv4(x, digits); } float_setsign(x, sgn); } /* evaluates cos x - 1 for |x| <= pi. This function may underflow, which is indicated by the return value 0 */ char _cosminus1( floatnum x, int digits) { float_abs(x); if (float_cmp(x, &cPiDiv4) <= 0) return _cosminus1ltPiDiv4(x, digits); _cos(x, digits); float_sub(x, x, &c1, digits); return 1; } /* evaluates sin x for |x| <= pi. */ void _sin( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &cPiDiv2) > 0) float_sub(x, &cPi, x, digits+1); if (float_cmp(x, &cPiDiv4) <= 0) _sinltPiDiv4(x, digits); else { float_sub(x, &cPiDiv2, x, digits+1); if (2*float_getexponent(x)+2 < - digits) float_setzero(x); else _cosminus1ltPiDiv4(x, digits); float_add(x, x, &c1, digits); } float_setsign(x, sgn); } /* evaluates tan x for |x| <= pi. A return value of 0 indicates that x = +/- pi/2 within small tolerances, so that tan x cannot be reliable computed */ char _tan( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &cPiDiv2) > 0) { float_sub(x, &cPi, x, digits+1); sgn = -sgn; } if (float_cmp(x, &cPiDiv4) <= 0) _tanltPiDiv4(x, digits); else { float_sub(x, &cPiDiv2, x, digits+1); if (float_iszero(x) || float_getexponent(x) < -digits) return 0; _tanltPiDiv4(x, digits); float_reciprocal(x, digits); } float_setsign(x, sgn); return 1; } char _trigreduce( floatnum x, int digits) { floatstruct tmp; int expx, save; signed char sgn; char odd; if (float_abscmp(x, &cPi) <= 0) return 1; expx = float_getexponent(x); if (expx > float_getlength(&cPi) - digits) return 0; save = float_setprecision(MAXDIGITS); float_create(&tmp); sgn = float_getsign(x); float_abs(x); float_divmod(&tmp, x, x, &cPi, INTQUOT); float_setprecision(save); odd = float_isodd(&tmp); if (odd) float_sub(x, x, &cPi, digits+1); if (sgn < 0) float_neg(x); float_free(&tmp); return 1; } void _sinpix( floatnum x, int digits) { char odd; odd = float_isodd(x); float_frac(x); float_mul(x, &cPi, x, digits+1); _sin(x, digits); if (odd) float_neg(x); } deepin-calculator-1.0.2/math/floattrig.h000066400000000000000000000036171325241207700202140ustar00rootroot00000000000000/* floattrig.h: trigonometry functions, based on floatnum. */ /* Copyright (C) 2007, 2008 Wolf Lammen. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: ookami1 gmx de mail: Wolf Lammen Oertzweg 45 22307 Hamburg Germany *************************************************************************/ #ifndef FLOATTRIG_H # define FLOATTRIG_H #include "floatnum.h" #ifdef __cplusplus extern "C" { #endif void _arctanlt1(floatnum x, int digits); void _arctan(floatnum x, int digits); void _arccosxplus1lt0_5(floatnum x, int digits); void _arcsinlt0_5(floatnum x, int digits); void _arccos(floatnum x, int digits); void _arccosxplus1(floatnum x, int digits); void _arcsin(floatnum x, int digits); char _cosminus1ltPiDiv4(floatnum x, int digits); void _sinltPiDiv4(floatnum x, int digits); void _tanltPiDiv4(floatnum x, int digits); void _cos(floatnum x, int digits); void _sin(floatnum x, int digits); char _tan(floatnum x, int digits); char _cosminus1(floatnum x, int digits); char _trigreduce(floatnum x, int digits); void _sinpix(floatnum x, int digits); #ifdef __cplusplus } #endif #endif /* FLOATTRIG_H */ deepin-calculator-1.0.2/math/hmath.cpp000066400000000000000000001503161325241207700176540ustar00rootroot00000000000000// HMath: C++ high precision math routines // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2007-2008, 2014 @heldercorreia // Copyright (C) 2008, 2009 Wolf Lammen // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "hmath.h" #include "floatcommon.h" #include "floatconst.h" #include "floatconvert.h" #include "floathmath.h" #include "rational.h" #include #include #include #include #include #include #include #define RATIONAL_TOL HNumber("1e-20") //TODO make this configurable #define HMATH_WORKING_PREC (DECPRECISION + 3) #define HMATH_EVAL_PREC (HMATH_WORKING_PREC + 2) //TODO should go into a separate format file // default scale for fall back in formatting #define HMATH_MAX_SHOWN 9 #define HMATH_BIN_MAX_SHOWN ((33219*HMATH_MAX_SHOWN)/10000 + 1) #define HMATH_OCT_MAX_SHOWN ((11073*HMATH_MAX_SHOWN)/10000 + 1) #define HMATH_HEX_MAX_SHOWN ((8305*HMATH_MAX_SHOWN)/10000 + 1) /*------------------------ Helper routines -------------------------*/ static void checkfullcancellation(cfloatnum op1, cfloatnum op2, floatnum r) { if (float_getlength(op1) != 0 && float_getlength(op2) != 0 && float_getlength(r) != 0) { // NaN or zero not involved in computation. int expr = float_getexponent(r); if (float_getexponent(op1) - expr >= HMATH_WORKING_PREC - 1 || float_getexponent(op2) - expr >= HMATH_WORKING_PREC - 1) float_setzero(r); } } static char checkAdd(floatnum dest, cfloatnum s1, cfloatnum s2, int digits) { if (float_add(dest, s1, s2, digits) && float_getsign(s1) + float_getsign(s2) == 0) checkfullcancellation(s1, s2, dest); return float_isnan(dest); } static char checkSub(floatnum dest, cfloatnum s1, cfloatnum s2, int digits) { if (float_sub(dest, s1, s2, digits) && float_getsign(s1) - float_getsign(s2) == 0) checkfullcancellation(s1, s2, dest); return float_isnan(dest); } static void h_init() { static bool h_initialized = false; if (!h_initialized) { h_initialized = true; //TODO related to formats, get rid of it. float_stdconvert(); } } static void checkpoleorzero(floatnum result, floatnum x) { if (float_getlength(result) == 0 || float_getlength(x) == 0) return; int expx = float_getexponent(x)-HMATH_WORKING_PREC+1; int expr = float_getexponent(result); if (expr <= expx) float_setzero(result); else if (expr >= -expx) { float_setnan(result); float_seterror(EvalUnstable); } } static char roundResult(floatnum x) { if (float_isnan(x)) // Avoids setting float_error. return 0; return float_round(x, x, HMATH_WORKING_PREC, TONEAREST); } /*--------------------------- HNumberPrivate --------------------*/ class HNumberPrivate { public: HNumberPrivate(); ~HNumberPrivate(); //TODO make this a variant floatstruct fnum; Error error; }; HNumberPrivate::HNumberPrivate() : error(Success) { h_init(); float_create(&fnum); } HNumberPrivate::~HNumberPrivate() { float_free(&fnum); } typedef char (*Float1ArgND)(floatnum x); typedef char (*Float1Arg)(floatnum x, int digits); typedef char (*Float2ArgsND)(floatnum result, cfloatnum p1, cfloatnum p2); typedef char (*Float2Args)(floatnum result, cfloatnum p1, cfloatnum p2, int digits); static Error checkNaNParam(const HNumberPrivate& v1, const HNumberPrivate* v2 = 0) { if (!float_isnan(&v1.fnum) && (!v2 || !float_isnan(&v2->fnum))) return Success; Error error = v1.error; if (error == Success && v2) error = v2->error; return error == 0? NoOperand : error; } void roundSetError(HNumberPrivate* dest) { dest->error = float_geterror(); floatnum dfnum = &dest->fnum; if (dest->error != Success) float_setnan(dfnum); if (!float_isnan(dfnum)) float_round(dfnum, dfnum, HMATH_WORKING_PREC, TONEAREST); } void call2Args(HNumberPrivate* dest, HNumberPrivate* n1, HNumberPrivate* n2, Float2Args func) { dest->error = checkNaNParam(*n1, n2); if (dest->error == Success) { floatnum dfnum = &dest->fnum; func(dfnum, &n1->fnum, &n2->fnum, HMATH_EVAL_PREC); roundSetError(dest); } } void call2ArgsND(HNumberPrivate* dest, HNumberPrivate* n1, HNumberPrivate* n2, Float2ArgsND func) { dest->error = checkNaNParam(*n1, n2); if (dest->error == Success) { floatnum dfnum = &dest->fnum; func(dfnum, &n1->fnum, &n2->fnum); roundSetError(dest); } } void call1Arg(HNumberPrivate* dest, HNumberPrivate* n, Float1Arg func) { dest->error = checkNaNParam(*n); if (dest->error == Success) { floatnum dfnum = &dest->fnum; float_copy(dfnum, &n->fnum, HMATH_EVAL_PREC); func(dfnum, HMATH_EVAL_PREC); roundSetError(dest); } } void call1ArgPoleCheck(HNumberPrivate* dest, HNumberPrivate* n, Float1Arg func) { dest->error = checkNaNParam(*n); if (dest->error == Success) { floatnum dfnum = &dest->fnum; float_copy(dfnum, &n->fnum, HMATH_EVAL_PREC); if (func(dfnum, HMATH_EVAL_PREC)) checkpoleorzero(dfnum, &n->fnum); roundSetError(dest); } } void call1ArgND(HNumberPrivate* dest, HNumberPrivate* n, Float1ArgND func) { dest->error = checkNaNParam(*n); if (dest->error == Success) { floatnum dfnum = &dest->fnum; float_copy(dfnum, &n->fnum, HMATH_EVAL_PREC); func(dfnum); roundSetError(dest); } } static char modwrap(floatnum result, cfloatnum p1, cfloatnum p2, int /*digits*/) { floatstruct tmp; float_create(&tmp); char ok = float_divmod(&tmp, result, p1, p2, INTQUOT); float_free(&tmp); return ok; } char idivwrap(floatnum result, cfloatnum p1, cfloatnum p2) { floatstruct tmp; int save = float_setprecision(DECPRECISION); float_create(&tmp); char ok = float_divmod(result, &tmp, p1, p2, INTQUOT); float_free(&tmp); float_setprecision(save); return ok; } /*-------------------------- HNumber -------------------*/ /** * Creates a new number. */ HNumber::HNumber() : d(new HNumberPrivate) { } /** * Copies from another number. */ HNumber::HNumber(const HNumber& hn) : d(new HNumberPrivate) { operator=(hn); } /** * Creates a new number from an integer value. */ HNumber::HNumber(int i) : d(new HNumberPrivate) { float_setinteger(&d->fnum, i); } /** * Creates a new number from a string. */ HNumber::HNumber(const char* str) : d(new HNumberPrivate) { t_itokens tokens; if ((d->error = parse(&tokens, &str)) == Success && *str == 0) d->error = float_in(&d->fnum, &tokens); float_geterror(); } HNumber::HNumber(const QJsonObject& json) : d(new HNumberPrivate) { *this = deSerialize(json); } /** * Destroys this number. */ HNumber::~HNumber() { delete d; } /** * Returns the error code kept with a NaN. */ Error HNumber::error() const { return d->error; } /** * Returns true if this number is Not a Number (NaN). */ bool HNumber::isNan() const { return float_isnan(&d->fnum) != 0; } /** * Returns true if this number is zero. */ bool HNumber::isZero() const { return float_iszero(&d->fnum) != 0; } /** * Returns true if this number is more than zero. */ bool HNumber::isPositive() const { return float_getsign(&d->fnum) > 0; } /** * Returns true if this number is less than zero. */ bool HNumber::isNegative() const { return float_getsign(&d->fnum) < 0; } /** * Returns true if this number is integer. */ bool HNumber::isInteger() const { return float_isinteger(&d->fnum) != 0; } void HNumber::serialize(QJsonObject& json) const { json["value"] = HMath::format(*this, Format::Fixed() + Format::Precision(DECPRECISION)); } HNumber HNumber::deSerialize(const QJsonObject& json) { HNumber result; if (json.contains("value")) { QString str = json["value"].toString(); str.replace(",", "."); result = HNumber(str.toLatin1().constData()); } return result; } /** * Returns the number as an int. * It is meant to convert small (integer) numbers only and no * checking is done whatsoever. */ int HNumber::toInt() const { return float_asinteger(&d->fnum); } /** * Assigns from another number. */ HNumber& HNumber::operator=(const HNumber& hn) { d->error = hn.error(); float_copy(&d->fnum, &hn.d->fnum, EXACT); return *this; } /** * Adds another number. */ HNumber HNumber::operator+(const HNumber& num) const { if (this->isZero()) return num; if (num.isZero()) return *this; HNumber result; call2Args(result.d, d, num.d, checkAdd); return result; } /** * Adds another number. */ HNumber& HNumber::operator+=(const HNumber& num) { return operator=(*this + num); } /** * Subtract from another number. */ HNumber operator-(const HNumber& n1, const HNumber& n2) { HNumber result; call2Args(result.d, n1.d, n2.d, checkSub); return result; } /** * Subtract from another number. */ HNumber& HNumber::operator-=(const HNumber& num) { return operator=(*this - num); } /** * Multiplies with another number. */ HNumber HNumber::operator*(const HNumber& num) const { HNumber result; call2Args(result.d, d, num.d, float_mul); return result; } /** * Multiplies with another number. */ HNumber& HNumber::operator*=(const HNumber& num) { return operator=(*this * num); } /** * Divides with another number. */ HNumber HNumber::operator/(const HNumber& num) const { HNumber result; call2Args(result.d, d, num.d, float_div); return result; } /** * Divides with another number. */ HNumber& HNumber::operator/=(const HNumber& num) { return operator=(*this / num); } /** * Modulo (rest of integer division) */ HNumber HNumber::operator%(const HNumber& num) const { HNumber result; call2Args(result.d, d, num.d, modwrap); return result; } /** * Returns -1, 0, 1 if *this is less than, equal to, or more than other. */ int HNumber::compare(const HNumber& other) const { int result = float_relcmp(&d->fnum, &other.d->fnum, HMATH_EVAL_PREC-1); float_geterror(); // clears error, if one operand was a NaN return result; } /** * Returns true if l is greater than r. */ bool operator>(const HNumber& l, const HNumber& r) { return l.compare(r) > 0; } /** * Returns true if l is less than r. */ bool operator<(const HNumber& l, const HNumber& r) { return l.compare(r) < 0; } /** * Returns true if l is greater than or equal to r. */ bool operator>=(const HNumber& l, const HNumber& r) { return l.compare(r) >= 0; } /** * Returns true if l is less than or equal to r. */ bool operator<=(const HNumber& l, const HNumber& r) { return l.compare(r) <= 0; } /** * Returns true if l is equal to r. */ bool operator==(const HNumber& l, const HNumber& r) { return l.compare(r) == 0; } /** * Returns true if l is not equal to r. */ bool operator!=(const HNumber& l, const HNumber& r) { return l.compare(r) != 0; } /** * Bitwise ANDs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber HNumber::operator&(const HNumber& num) const { HNumber result; call2ArgsND(result.d, d, num.d, float_and); return result; } /** * Bitwise ANDs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber& HNumber::operator&=(const HNumber& num) { return operator=(*this & num); } /** * Bitwise ORs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber HNumber::operator|(const HNumber& num) const { HNumber result; call2ArgsND(result.d, d, num.d, float_or); return result; } /** * Bitwise ORs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber& HNumber::operator|=(const HNumber& num) { return operator=(*this | num); } /** * Bitwise XORs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber HNumber::operator^(const HNumber& num) const { HNumber result; call2ArgsND(result.d, d, num.d, float_xor); return result; } /** * Bitwise XORs the integral parts of both operands. * Yields NaN, if any operand exeeds the logic range */ HNumber& HNumber::operator^=(const HNumber& num) { return operator=(*this ^ num); } /** * Bitwise NOTs the integral part *this. * Yields NaN, if *this exeeds the logic range */ HNumber HNumber::operator~() const { HNumber result; call1ArgND(result.d, d, float_not); return result; } /** * Changes the sign. */ HNumber operator-(const HNumber& x) { HNumber result; call1ArgND(result.d, x.d, float_neg); return result; } /** * Shifts the integral part of <*this> to the left by * the parameters value's bits. Zeros are shifted in * to the right, shifted out bits are dropped. * Yields NaN, if the operand exeeds the logic range, * or the shift count is not a non-negative integer. */ HNumber HNumber::operator<<(const HNumber& num) const { HNumber result; call2ArgsND(result.d, d, num.d, float_shl); return result; } /** * Shifts the integral part of <*this> to the right by * the parameters value's bits. The most significand * bit is duplicated to the left, shifted out bits are dropped * (signed or arithmethic shift right). * Yields NaN, if the operand exeeds the logic range, * or the shift count is not a non-negative integer. */ HNumber HNumber::operator>>(const HNumber& num) const { HNumber result; call2ArgsND(result.d, d, num.d, float_shr); return result; } HNumber::Format::Format() : base(Base::Null) , radixChar(RadixChar::Null) , mode(Mode::Null) , precision(PrecisionNull) { } HNumber::Format::Format(const HNumber::Format& other) : base(other.base) , radixChar(other.radixChar) , mode(other.mode) , precision(other.precision) { } HNumber::Format HNumber::Format::operator+(const HNumber::Format& other) const { Format result; result.base = (this->base != Base::Null) ? this->base : other.base; result.radixChar = (this->radixChar != RadixChar::Null) ? this->radixChar : other.radixChar; result.mode = (this->mode != Mode::Null) ? this->mode : other.mode; result.precision = (this->precision != PrecisionNull) ? this->precision : other.precision; return result; } HNumber::Format HNumber::Format::Binary() { Format result; result.base = Base::Binary; return result; } HNumber::Format HNumber::Format::Octal() { Format result; result.base = Base::Octal; return result; } HNumber::Format HNumber::Format::Decimal() { Format result; result.base = Base::Decimal; return result; } HNumber::Format HNumber::Format::Hexadecimal() { Format result; result.base = Base::Hexadecimal; return result; } HNumber::Format HNumber::Format::Precision(int prec) { Format result; result.precision = prec; return result; } HNumber::Format HNumber::Format::Point() { Format result; result.radixChar = RadixChar::Point; return result; } HNumber::Format HNumber::Format::Comma() { Format result; result.radixChar = RadixChar::Comma; return result; } HNumber::Format HNumber::Format::General() { Format result; result.mode = Mode::General; return result; } HNumber::Format HNumber::Format::Fixed() { Format result; result.mode = Mode::Fixed; return result; } HNumber::Format HNumber::Format::Scientific() { Format result; result.mode = Mode::Scientific; return result; } HNumber::Format HNumber::Format::Engineering() { Format result; result.mode = Mode::Engineering; return result; } namespace { char* _doFormat(cfloatnum x, signed char base, signed char expbase, char outmode, int prec, unsigned flags) { t_otokens tokens; char intbuf[BINPRECISION+1]; char fracbuf[BINPRECISION+1]; int sz = 0; char* str = nullptr; switch (base) { case 2: sz = BINPRECISION+1; break; case 8: sz = OCTPRECISION+1; break; case 10: sz = DECPRECISION+1; break; case 16: sz = HEXPRECISION+1; break; } tokens.intpart.sz = sz; tokens.intpart.buf = intbuf; tokens.fracpart.sz = sz; tokens.fracpart.buf = fracbuf; floatstruct tmp; float_create(&tmp); float_copy(&tmp, x, DECPRECISION + 2); if (float_out(&tokens, &tmp, prec, base, outmode) == Success) { sz = cattokens(nullptr, -1, &tokens, expbase, flags); str = (char*)malloc(sz); cattokens(str, sz, &tokens, expbase, flags); } float_free(&tmp); return str; } /** * Formats the given number as string, using specified decimal digits. * Note that the returned string must be freed. */ char* formatFixed(cfloatnum x, int prec, int base = 10) { unsigned flags = IO_FLAG_SUPPRESS_PLUS + IO_FLAG_SUPPRESS_DOT + IO_FLAG_SUPPRESS_EXPZERO; if (base != 10) flags += IO_FLAG_SHOW_BASE + IO_FLAG_SHOW_EXPBASE; if (prec < 0) { flags |= IO_FLAG_SUPPRESS_TRL_ZERO; prec = HMATH_MAX_SHOWN; } char* result = _doFormat(x, base, base, IO_MODE_FIXPOINT, prec, flags); return result ? result : _doFormat(x, base, base, IO_MODE_SCIENTIFIC, HMATH_MAX_SHOWN, flags); } /** * Formats the given number as string, in scientific format. * Note that the returned string must be freed. */ char* formatScientific(cfloatnum x, int prec, int base = 10) { unsigned flags = IO_FLAG_SUPPRESS_PLUS + IO_FLAG_SUPPRESS_DOT + IO_FLAG_SUPPRESS_EXPPLUS; if (base != 10) flags += IO_FLAG_SHOW_BASE + IO_FLAG_SHOW_EXPBASE; if (prec < 0) { flags |= IO_FLAG_SUPPRESS_TRL_ZERO; prec = HMATH_MAX_SHOWN; } return _doFormat(x, base, base, IO_MODE_SCIENTIFIC, prec, flags); } /** * Formats the given number as string, in engineering notation. * Note that the returned string must be freed. */ char* formatEngineering(cfloatnum x, int prec, int base = 10) { unsigned flags = IO_FLAG_SUPPRESS_PLUS + IO_FLAG_SUPPRESS_EXPPLUS; if (base != 10) flags += IO_FLAG_SHOW_BASE + IO_FLAG_SHOW_EXPBASE; if (prec <= 1) { flags |= IO_FLAG_SUPPRESS_TRL_ZERO + IO_FLAG_SUPPRESS_DOT; prec = HMATH_MAX_SHOWN; } return _doFormat(x, base, base, IO_MODE_ENG, prec, flags); } /** * Formats the given number as string, using specified decimal digits. * Note that the returned string must be freed. */ char* formatGeneral(cfloatnum x, int prec, int base = 10) { // find the exponent and the factor int expd = float_getexponent(x); char* str; if (expd > 5) str = formatScientific(x, prec, base); else if (expd < -4) str = formatScientific(x, prec, base); else if ((expd < 0) && (prec >= 0) && (expd < -prec)) str = formatScientific(x, prec, base); else str = formatFixed(x, prec, base); return str; } } /* unnamed namespace */ /** * Formats the given number as string, using specified decimal digits. */ QString HMath::format(const HNumber& hn, HNumber::Format format) { char* rs = 0; if (format.precision < 0) // This includes PrecisionNull format.precision = -1; int base; switch (format.base) { case HNumber::Format::Base::Binary: base = 2; break; case HNumber::Format::Base::Octal: base = 8; break; case HNumber::Format::Base::Hexadecimal: base = 16; break; case HNumber::Format::Base::Decimal: case HNumber::Format::Base::Null: default: base = 10; break; } switch (format.mode) { case HNumber::Format::Mode::Fixed: rs = formatFixed(&hn.d->fnum, format.precision, base); break; case HNumber::Format::Mode::Scientific: rs = formatScientific(&hn.d->fnum, format.precision, base) ; break; case HNumber::Format::Mode::Engineering: rs = formatEngineering(&hn.d->fnum, format.precision, base); break; case HNumber::Format::Mode::General: default: rs = formatGeneral(&hn.d->fnum, format.precision, base); } QString result(rs); free(rs); return result; } /** * Converts radians to degrees. */ HNumber HMath::rad2deg(const HNumber& angle) { return angle * (HNumber(180) / HMath::pi()); } /** * Converts degrees to radians. */ HNumber HMath::deg2rad(const HNumber& angle) { return angle * (HMath::pi() / HNumber(180)); } /** * Returns the constant e (Euler's number). */ HNumber HMath::e() { HNumber value; float_copy(&value.d->fnum, &cExp, HMATH_EVAL_PREC); return value; } /** * Returns the constant Pi. */ HNumber HMath::pi() { HNumber value; float_copy(&value.d->fnum, &cPi, HMATH_EVAL_PREC); return value; } /** * Returns the constant Phi (golden number). */ HNumber HMath::phi() { HNumber value; float_copy(&value.d->fnum, &cPhi, HMATH_EVAL_PREC); return value; } /** * Returns a NaN (Not a Number) with error set to * passed parameter. */ HNumber HMath::nan(Error error) { HNumber result; result.d->error = error; return result; } /** * Returns the maximum of two numbers. */ HNumber HMath::max(const HNumber& n1, const HNumber& n2) { switch (float_cmp(&n1.d->fnum, &n2.d->fnum)) { case 0: case 1: return n1; case -1: return n2; default: return HMath::nan(checkNaNParam(*n1.d, n2.d)); } } /** * Returns the minimum of two numbers. */ HNumber HMath::min(const HNumber& n1, const HNumber& n2) { switch (float_cmp(&n1.d->fnum, &n2.d->fnum)) { case 0: case 1: return n2; case -1: return n1; default: return HMath::nan(checkNaNParam(*n1.d, n2.d)); } } /** * Returns the absolute value of n. */ HNumber HMath::abs(const HNumber& n) { HNumber result; call1ArgND(result.d, n.d, float_abs); return result; } /** * Rounds n to the specified decimal digits. */ HNumber HMath::round(const HNumber& n, int prec) { if (n.isNan()) return HMath::nan(checkNaNParam(*n.d)); HNumber result(n); floatnum rnum = &result.d->fnum; int exp = float_getexponent(rnum); // Avoid exponent overflow later. if (prec > HMATH_WORKING_PREC && exp > 0) prec = HMATH_WORKING_PREC; if (prec < 0 && -exp-1 > prec) float_setzero(rnum); else if (exp + prec < HMATH_WORKING_PREC) { float_addexp(rnum, prec); float_roundtoint(rnum, TONEAREST); float_addexp(rnum, -prec); } return result; } /** * Truncates n to the specified decimal digits. */ HNumber HMath::trunc(const HNumber& n, int prec) { if (n.isNan()) return HMath::nan(checkNaNParam(*n.d)); HNumber result(n); floatnum rnum = &result.d->fnum; int exp = float_getexponent(rnum); // Avoid exponent overflow later on. if (prec > HMATH_WORKING_PREC && exp > 0) prec = HMATH_WORKING_PREC; if (prec < 0 && -exp-1 > prec) float_setzero(rnum); else if (exp + prec < HMATH_WORKING_PREC) { float_addexp(rnum, prec); float_roundtoint(rnum, TOZERO); float_addexp(rnum, -prec); } return result; } /** * Returns the integer part of n. */ HNumber HMath::integer(const HNumber& n) { HNumber result; call1ArgND(result.d, n.d, float_int); return result; } /** * Returns the fraction part of n. */ HNumber HMath::frac(const HNumber& n) { HNumber result; call1ArgND(result.d, n.d, float_frac); return result; } #define CHECK_NAN \ if (n.isNan()) \ return HMath::nan(checkNaNParam(*n.d)); #define RETURN_IF_NEAR_INT \ HNumber nearest_int(n); \ float_roundtoint(&nearest_int.d->fnum, TONEAREST); \ /* Note: float_relcmp doesn't work here, because it's doesn't check the relative */ \ /* tolerance if exponents are not the same. */ \ /* FIXME: Put this value as parameter. */ \ /* Kudos to the guy who can figure out why we need such a small tolerance here. */ \ /* 1e-70 does not work, but 1e-10000 does. */ \ if (HMath::abs(n - nearest_int) < HNumber("1e-100") * HMath::abs(n + nearest_int)) /* FIXME: Make configurable. */ \ return nearest_int; \ /** * Returns the floor of n. */ HNumber HMath::floor(const HNumber& n) { CHECK_NAN; RETURN_IF_NEAR_INT; // Actual rounding, if needed. HNumber r(n); float_roundtoint(&r.d->fnum, TOMINUSINFINITY); return r; } /** * Returns the ceiling of n. */ HNumber HMath::ceil(const HNumber& n) { CHECK_NAN; RETURN_IF_NEAR_INT; // Actual rounding, if needed. HNumber r(n); float_roundtoint(&r.d->fnum, TOPLUSINFINITY); return r; } /** * Returns the greatest common divisor of n1 and n2. */ HNumber HMath::gcd(const HNumber& n1, const HNumber& n2) { if (!n1.isInteger() || !n2.isInteger()) { Error error = checkNaNParam(*n1.d, n2.d); if (error != Success) return HMath::nan(error); return HMath::nan(TypeMismatch); } HNumber a = abs(n1); HNumber b = abs(n2); if (a == 0) return b; if (b == 0) return a; // Run Euclidean algorithm. while (true) { a = a % b; if (a == 0) return b; b = b % a; if (b == 0) return a; } } /** * Performs an integer divide. */ HNumber HMath::idiv(const HNumber& dividend, const HNumber& divisor) { HNumber result; call2ArgsND(result.d, dividend.d, divisor.d, idivwrap); if (result.error() == TooExpensive) result.d->error = Overflow; return result; } /** * Returns the square root of n. If n is negative, returns NaN. */ HNumber HMath::sqrt(const HNumber& n) { HNumber result; call1Arg(result.d, n.d, float_sqrt); return result; } /** * Returns the cube root of n. */ HNumber HMath::cbrt(const HNumber& n) { if (n.isNan()) return HMath::nan(checkNaNParam(*n.d)); if (n.isZero()) return n; HNumber r; floatnum rnum = &r.d->fnum; // iterations to approximate result // X[i+1] = (2/3)X[i] + n / (3 * X[i]^2)) // initial guess = sqrt(n) // r = X[i], q = X[i+1], a = n floatstruct a, q; float_create(&a); float_create(&q); float_copy(&a, &n.d->fnum, HMATH_EVAL_PREC); signed char sign = float_getsign(&a); float_abs(&a); int expn = float_getexponent(&a); float_setexponent(&a, expn % 3); expn /= 3; int digits = 0; float_copy(&q, &a, 2); float_sqrt(&q, 2); while (digits < HMATH_EVAL_PREC/2 + 3) { digits = 4 * digits + 2; if (digits > HMATH_EVAL_PREC+2) digits = HMATH_EVAL_PREC+2; float_move(rnum, &q); float_mul(&q, rnum, rnum, digits); float_div(&q, &a, &q, digits); float_add(&q, &q, rnum, digits); float_add(&q, &q, rnum, digits); float_div(&q, &q, &c3, digits); float_sub(rnum, rnum, &q, 3); if (!float_iszero(rnum)) digits = float_getexponent(&q) - float_getexponent(rnum); } float_move(rnum, &q); float_free(&q); float_free(&a); float_setsign(rnum, sign); float_addexp(rnum, expn); roundResult(&r.d->fnum); return r; } /** * Raises n1 to an integer n. */ HNumber HMath::raise(const HNumber& n1, int n) { HNumber r; float_raisei(&r.d->fnum, &n1.d->fnum, n, HMATH_EVAL_PREC); roundSetError(r.d); return r; } /** * Raises n1 to n2. */ HNumber HMath::raise(const HNumber& n1, const HNumber& n2) { HNumber result; HNumber temp = n1; Rational exp; bool change_sgn=false; if (n1.isNegative() && !n2.isInteger()){ //Try to convert n2 to a Rational. If n2 is not rational, return NaN. // For negative bases only allow odd denominators. exp = Rational(n2); if (abs(exp.toHNumber() - n2) >= RATIONAL_TOL || (n1.isNegative() && exp.denominator()%2 == 0)) return HMath::nan(OutOfDomain); if (n1.isNegative() && !n2.isInteger()) { temp = -temp; change_sgn = true; } } call2Args(result.d, temp.d, n2.d, float_raise); result *= (change_sgn) ? -1 : 1; return result; } /** * Returns e raised to x. */ HNumber HMath::exp(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_exp); return result; }; /** * Returns the natural logarithm of x. * If x is non positive, returns NaN. */ HNumber HMath::ln(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_ln); return result; } /** * Returns the common logarithm of x. * If x is non positive, returns NaN. */ HNumber HMath::lg(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_lg); return result; } /** * Returns the binary logarithm of x. * If x is non positive, returns NaN. */ HNumber HMath::lb(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_lb); return result; } /** * Returns the logarithm of x to base. * If x is non positive, returns NaN. */ HNumber HMath::log(const HNumber& base, const HNumber& x) { return lg(x) / lg(base); } /** * Returns the sine of x. Note that x must be in radians. */ HNumber HMath::sin(const HNumber& x) { HNumber result; call1ArgPoleCheck(result.d, x.d, float_sin); return result; } /** * Returns the cosine of x. Note that x must be in radians. */ HNumber HMath::cos(const HNumber& x) { HNumber result; call1ArgPoleCheck(result.d, x.d, float_cos); return result; } /** * Returns the tangent of x. Note that x must be in radians. */ HNumber HMath::tan(const HNumber& x) { HNumber result; call1ArgPoleCheck(result.d, x.d, float_tan); return result; } /** * Returns the cotangent of x. Note that x must be in radians. */ HNumber HMath::cot(const HNumber& x) { return cos(x) / sin(x); } /** * Returns the secant of x. Note that x must be in radians. */ HNumber HMath::sec(const HNumber& x) { return HNumber(1) / cos(x); } /** * Returns the cosecant of x. Note that x must be in radians. */ HNumber HMath::csc(const HNumber& x) { return HNumber(1) / sin(x); } /** * Returns the arc tangent of x. */ HNumber HMath::arctan(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_arctan); return result; } /** * Returns the angle formed by the vector (x, y) and the x-axis. */ HNumber HMath::arctan2(const HNumber& x, const HNumber& y) { if (y.isZero()) { if (x.isNegative()) return HMath::pi(); if (x.isZero()) return HMath::nan(OutOfDomain); return HNumber(0); } else { HNumber phi = HMath::arctan(HMath::abs(y / x)); if (x.isNegative()) return (HMath::pi() - phi) * HMath::sgn(y); if (x.isZero()) return HMath::pi()/HNumber(2)*HMath::sgn(y); return phi * HMath::sgn(y); } } /** * Returns the arc sine of x. */ HNumber HMath::arcsin(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_arcsin); return result; }; /** * Returns the arc cosine of x. */ HNumber HMath::arccos(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_arccos); return result; }; /** * Returns the hyperbolic sine of x. */ HNumber HMath::sinh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_sinh); return result; } /** * Returns the hyperbolic cosine of x. */ HNumber HMath::cosh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_cosh); return result; } /** * Returns the hyperbolic tangent of x. */ HNumber HMath::tanh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_tanh); return result; } /** * Returns the area hyperbolic sine of x. */ HNumber HMath::arsinh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_arsinh); return result; } /** * Returns the area hyperbolic cosine of x. */ HNumber HMath::arcosh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_arcosh); return result; } /** * Returns the area hyperbolic tangent of x. */ HNumber HMath::artanh(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_artanh); return result; } /** * Returns the Gamma function. */ HNumber HMath::gamma(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_gamma); return result; } /** * Returns ln(abs(Gamma(x))). */ HNumber HMath::lnGamma(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_lngamma); return result; } /** * Returns signum x. */ HNumber HMath::sgn(const HNumber& x) { if (x.isNan()) return HMath::nan(checkNaNParam(*x.d)); return float_getsign(&x.d->fnum); } /** * Returns the binomial coefficient of n and r. * Is any of n and r negative or a non-integer, * 1/(n+1)*B(r+1, n-r+1)) is returned, where * B(x,y) is the complete Beta function */ HNumber HMath::nCr(const HNumber& n, const HNumber& r) { Error error = checkNaNParam(*n.d, r.d); if (error != Success) return HMath::nan(error); if (r.isInteger() && r < 0) return HNumber(0); // use symmetry nCr(n, r) == nCr(n, n-r) to find r1 such // 2*r1 <= n and nCr(n, r) == nCr(n, r1) HNumber r1 = (r + r > n) ? n - r : r; HNumber r2 = n - r1; if (r1 >= 0) { if (n.isInteger() && r1.isInteger() && n <= 1000 && r1 <= 50) return factorial(n, r2+1) / factorial(r1, 1); HNumber result(n); floatnum rnum = &result.d->fnum; floatstruct fn, fr; float_create(&fn); float_create(&fr); float_copy(&fr, &r1.d->fnum, HMATH_EVAL_PREC); float_copy(&fn, rnum, EXACT); float_sub(rnum, rnum, &fr, HMATH_EVAL_PREC) && float_add(&fn, &fn, &c1, HMATH_EVAL_PREC) && float_add(&fr, &fr, &c1, HMATH_EVAL_PREC) && float_add(rnum, rnum, &c1, HMATH_EVAL_PREC) && float_lngamma(&fn, HMATH_EVAL_PREC) && float_lngamma(&fr, HMATH_EVAL_PREC) && float_lngamma(rnum, HMATH_EVAL_PREC) && float_add(rnum, rnum, &fr, HMATH_EVAL_PREC) && float_sub(rnum, &fn, rnum, HMATH_EVAL_PREC) && float_exp(rnum, HMATH_EVAL_PREC); float_free(&fn); float_free(&fr); roundSetError(result.d); return result; } if (r2 >= 0 || !r2.isInteger()) return factorial(n, r1+1)/factorial(r2, 1); return 0; } /** * Returns the permutation of n elements chosen r elements. */ HNumber HMath::nPr(const HNumber& n, const HNumber& r) { return factorial(n, (n-r+1)); } /** * Returns the falling Pochhammer symbol x*(x-1)*..*base. * For base == 1, this is the usual factorial x!, what this * function is named after. * This function has been extended using the Gamma function, * so that actually Gamma(x+1)/Gamma(base) is computed, a * value that equals the falling Pochhammer symbol, when * x - base is an integer, but allows other differences as well. */ HNumber HMath::factorial(const HNumber& x, const HNumber& base) { floatstruct tmp; if (float_cmp(&c1, &base.d->fnum) == 0) { HNumber result; call1Arg(result.d, x.d, float_factorial); return result; } float_create(&tmp); HNumber r(base); float_sub(&tmp, &x.d->fnum, &base.d->fnum, HMATH_EVAL_PREC) && float_add(&tmp, &tmp, &c1, HMATH_EVAL_PREC) && float_pochhammer(&r.d->fnum, &tmp, HMATH_EVAL_PREC); roundSetError(r.d); float_free(&tmp); return r; } static bool checkpn(const HNumber& p, const HNumber& n) { return n.isInteger() && !n.isNegative() && !p.isNan() && !p.isNegative() && p <= 1; } /** * Calculates the binomial discrete distribution probability mass function: * \f[X{\sim}B(n,p)\f] * \f[\Pr(X=k|n,p)={n\choose k}p^{k}(1-p)^{n-k}\f] * * \param[in] k the number of probed exact successes * \param[in] n the number of trials * \param[in] p the probability of success in a single trial * * \return the probability of exactly \p k successes, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::binomialPmf(const HNumber& k, const HNumber& n, const HNumber& p) { if (!k.isInteger() || !checkpn(p, n)) return HMath::nan(InvalidParam); HNumber result = nCr(n, k); if (result.isZero()) return result; // special case: powers of zero, 0^0 == 1 in this context if (p.isInteger()) return (int)(p.isZero()? k.isZero() : n == k); return result * raise(p, k) * raise(HNumber(1) - p, n - k); } /** * Calculates the binomial cumulative distribution function: * \f[X{\sim}B(n,p)\f] * \f[\Pr(X \leq k|n,p)=\sum_{i=0}^{k}{n\choose i}p^{i}(1-p)^{n-i}\f] * * \param[in] k the maximum number of probed successes * \param[in] n the number of trials * \param[in] p the probability of success in a single trial * * \return the probability of up to \p k successes, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::binomialCdf(const HNumber& k, const HNumber& n, const HNumber& p) { // FIXME: Use the regularized incomplete Beta function to avoid the potentially very expensive loop. if (!k.isInteger() || n.isNan()) return HMath::nan(); // Initiates summation, checks arguments as well. HNumber summand = binomialPmf(0, n, p); if (summand.isNan()) return summand; HNumber one(1); // Some early out results. if (k.isNegative()) return 0; if (k >= n) return one; HNumber pcompl = one - p; if (p.isInteger()) return pcompl; // use reflexion formula to limit summation if (k + k > n && k + one >= p * (n + one)) return one - binomialCdf(n - k - one, n, pcompl); // loop adding binomialPdf HNumber result(summand); for (HNumber i(0); i < k;) { summand *= p * (n-i); i += one; summand /= pcompl * i; result += summand; } return result; } /** * Calculates the expected value of a binomially distributed random variable: * \f[X{\sim}B(n,p)\f] * \f[E(X)=np\f] * * \param[in] n the number of trials * \param[in] p the probability of success in a single trial * * \return the expected value of the variable, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::binomialMean(const HNumber& n, const HNumber& p) { if (!checkpn(p, n)) return HMath::nan(); return n * p; } /** * Calculates the variance of a binomially distributed random variable: * \f[X{\sim}B(n,p)\f] * \f[Var(X)=np(1-p)\f] * * \param[in] n the number of trials * \param[in] p the probability of success in a single trial * * \return the variance of the variable, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::binomialVariance(const HNumber& n, const HNumber& p) { return binomialMean(n, p) * (HNumber(1) - p); } static bool checkNMn(const HNumber& N, const HNumber& M, const HNumber& n) { return N.isInteger() && !N.isNegative() && M.isInteger() && !M.isNegative() && n.isInteger() && !n.isNegative() && HMath::max(M, n) <= N; } /** * Calculates the hypergeometric discrete distribution probability mass * function: * \f[X{\sim}H(N,M,n)\f] * \f[\Pr(X=k|N,M,n)=\frac{{M\choose k}{N-M\choose n-k}}{{N\choose n}}\f] * * \param[in] k the number of probed exact successes * \param[in] N the number of total elements * \param[in] M the number of success elements * \param[in] n the number of selected elements * * \return the probability of exactly \p k successes, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::hypergeometricPmf(const HNumber& k, const HNumber& N, const HNumber& M, const HNumber& n) { if (!k.isInteger() || !checkNMn(N, M, n)) return HMath::nan(); return HMath::nCr(M, k) * HMath::nCr(N - M, n - k) / HMath::nCr(N, n); } /** * Calculates the hypergeometric cumulative distribution function: * \f[X{\sim}H(N,M,n)\f] * \f[\Pr(X\leq k|N,M,n)= * \sum_{i=0}^{k}\frac{{M\choose k}{N-M\choose n-k}}{{N\choose n}}\f] * * \param[in] k the maximum number of probed successes * \param[in] N the number of total elements * \param[in] M the number of success elements * \param[in] n the number of selected elements * * \return the probability of up to \p k successes, otherwise \p NaN if the * function is not defined for the specified parameters. */ HNumber HMath::hypergeometricCdf(const HNumber& k, const HNumber& N, const HNumber& M, const HNumber& n) { // Lowest index of non-zero summand in loop. HNumber c = M + n - N; HNumber i = max(c, 0); // First summand in loop, do the parameter checking here. HNumber summand = HMath::hypergeometricPmf(i, N, M, n); if (!k.isInteger() || summand.isNan()) return HMath::nan(); // Some early out results. HNumber one(1); if (k >= M || k >= n) return one; if (i > k) return 0; // Use reflexion formula to limit summations. Numerically unstable where the result is near 0, disable for now. // if (k + k > n) // return one - hypergeometricCdf(n - k - 1, N, N - M, n); HNumber result = summand; for (; i < k;) { summand *= (M - i) * (n - i); i += one; summand /= i * (i - c); result += summand; } return result; } /** * Calculates the expected value of a hypergeometrically distributed random * variable: * \f[X{\sim}H(N,M,n)\f] * \f[E(X)=n\frac{M}{N}\f] * * \param[in] N the number of total elements * \param[in] M the number of success elements * \param[in] n the number of selected elements * * \return the expected value of the variable, otherwise \p NaN if the * function is not defined for the specified parameter. */ HNumber HMath::hypergeometricMean(const HNumber& N, const HNumber& M, const HNumber& n) { if (!checkNMn(N, M, n)) return HMath::nan(); return n * M / N; } /** * * Calculates the variance of a hypergeometrically distributed random variable: * \f[X{\sim}H(N,M,n)\f] * \f[Var(X)=\frac{n\frac{M}{N}(1-\frac{M}{N})(N-n)}{N-1}\f] * * \param[in] N the number of total elements * \param[in] M the number of success elements * \param[in] n the number of selected elements * * \return the variance of the variable, otherwise \p NaN if the function is * not defined for the specified parameter. */ HNumber HMath::hypergeometricVariance(const HNumber& N, const HNumber& M, const HNumber& n) { return (hypergeometricMean(N, M, n) * (HNumber(1) - M / N) * (N - n)) / (N - HNumber(1)); } /** * * Calculates the poissonian discrete distribution probability mass function: * \f[X{\sim}P(\lambda)\f] * \f[\Pr(X=k|\lambda)=\frac{e^{-\lambda}\lambda^k}{k!}\f] * * \param[in] k the number of event occurrences * \param[in] l the expected number of occurrences that occur in an interval * * \return the probability of exactly \p k event occurrences, otherwise \p NaN * if the function is not defined for the specified parameters. */ HNumber HMath::poissonPmf(const HNumber& k, const HNumber& l) { if (!k.isInteger() || l.isNan() || l.isNegative()) return HMath::nan(); if (k.isNegative()) return 0; if (l.isZero()) return int(k.isZero()); return exp(-l) * raise(l, k) / factorial(k); } /** * Calculates the poissonian cumulative distribution function: * \f[X{\sim}P(\lambda)\f] * \f[\Pr(X\leq k|\lambda)=\sum_{i=0}^{k}\frac{e^{-\lambda}\lambda^k}{k!}\f] * * \param[in] k the maximum number of event occurrences * \param[in] l the expected number of occurrences that occur in an interval * * \return the probability of up to \p k event occurrences, otherwise \p NaN * if the function is not defined for the specified parameters. */ HNumber HMath::poissonCdf(const HNumber& k, const HNumber& l) { // FIXME: Use the incomplete gamma function to avoid a potentially expensive loop. if (!k.isInteger() || l.isNan() || l.isNegative()) return HMath::nan(); if (k.isNegative()) return 0; HNumber one(1); if (l.isZero()) return one; HNumber summand = one; HNumber result = one; for (HNumber i = one; i <= k; i += one) { summand *= l / i; result += summand; } result = exp(-l) * result; return result; } /** * Calculates the expected value of a Poisson distributed random variable: * \f[X{\sim}P(\lambda)\f] * \f[E(X)=\lambda\f] * * \param[in] l the expected number of occurrences that occur in an interval * * \return the expected value of the variable, otherwise \p NaN if the * function is not defined for the specified parameter. */ HNumber HMath::poissonMean(const HNumber& l) { if (l.isNan() || l.isNegative()) return HMath::nan(); return l; } /** * Calculates the variance of a Poisson distributed random variable: * \f[X{\sim}P(\lambda)\f] * \f[Var(X)=\lambda\f] * * \param[in] l the expected number of occurrences that occur in an interval * * \return the variance of the variable, otherwise \p NaN if the function is * not defined for the specified parameter. */ HNumber HMath::poissonVariance(const HNumber& l) { return poissonMean(l); } /** * Returns the erf function (related to normal distribution). */ HNumber HMath::erf(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_erf); return result; } /** * Returns the complementary erf function (related to normal distribution). */ HNumber HMath::erfc(const HNumber& x) { HNumber result; call1Arg(result.d, x.d, float_erfc); return result; } /** * Restricts a logic value to a given bit size. */ HNumber HMath::mask(const HNumber& val, const HNumber& bits) { if (val.isNan() || bits == 0 || bits >= LOGICRANGE || !bits.isInteger()) return HMath::nan(); return val & ~(HNumber(-1) << HNumber(bits)); } /** * sign-extends an unsigned value */ HNumber HMath::sgnext(const HNumber& val, const HNumber& bits) { if (val.isNan() || bits == 0 || bits >= LOGICRANGE || !bits.isInteger()) return HMath::nan(); HNumber ofs = HNumber(LOGICRANGE) - bits; return (val << ofs) >> ofs; } /** * For bits >= 0 does an arithmetic shift right, for bits < 0 a shift left. */ HNumber HMath::ashr(const HNumber& val, const HNumber& bits) { if (val.isNan() || bits <= -LOGICRANGE || bits >= LOGICRANGE || !bits.isInteger()) return HMath::nan(); if (bits >= 0) return val >> bits; return val << -bits; } /** * Decode an IEEE-754 bit pattern with the default exponent bias */ HNumber HMath::decodeIeee754(const HNumber& val, const HNumber& exp_bits, const HNumber& significand_bits) { return HMath::decodeIeee754(val, exp_bits, significand_bits, HMath::raise(2, exp_bits - 1) - 1); } /** * Decode an IEEE-754 bit pattern with the given parameters */ HNumber HMath::decodeIeee754(const HNumber& val, const HNumber& exp_bits, const HNumber& significand_bits, const HNumber& exp_bias) { if (val.isNan() || exp_bits <= 0 || exp_bits >= LOGICRANGE || !exp_bits.isInteger() || significand_bits <= 0 || significand_bits >= LOGICRANGE || !significand_bits.isInteger() || !exp_bias.isInteger()) return HMath::nan(); HNumber sign(HMath::mask(val >> (exp_bits + significand_bits), 1).isZero() ? 1 : -1); HNumber exp = HMath::mask(val >> significand_bits, exp_bits); // <=> '0.' b_x b_x-1 b_x-2 ... b_0 HNumber significand = HMath::mask(val, significand_bits) * HMath::raise(2, -significand_bits); if (exp.isZero()) { // Exponent 0, subnormal value or zero. return sign * significand * HMath::raise(2, exp - exp_bias + 1); } if (exp - HMath::raise(2, exp_bits) == -1) { // Exponent all 1... if (significand.isZero()) // ...and signficand 0, infinity. // TODO: Represent infinity as something other than NaN? return HNumber(); // ...and significand not 0, NaN. return HMath::nan(); } return sign * (significand + 1) * HMath::raise(2, exp - exp_bias); // Normalised value. } /** * Encode a value in a IEEE-754 binary representation with the default exponent bias */ HNumber HMath::encodeIeee754(const HNumber& val, const HNumber& exp_bits, const HNumber& significand_bits) { return HMath::encodeIeee754(val, exp_bits, significand_bits, HMath::raise(2, exp_bits - 1) - 1); } /** * Encode a value in a IEEE-754 binary representation */ HNumber HMath::encodeIeee754(const HNumber& val, const HNumber& exp_bits, const HNumber& significand_bits, const HNumber& exp_bias) { if (exp_bits <= 0 || exp_bits >= LOGICRANGE || !exp_bits.isInteger() || significand_bits <= 0 || significand_bits >= LOGICRANGE || !significand_bits.isInteger() || !exp_bias.isInteger()) return HMath::nan(); HNumber sign_bit; HNumber significand; HNumber exponent; HNumber min_exp(1 - exp_bias); HNumber max_exp(HMath::raise(2, exp_bits) - 2 - exp_bias); if (val.isNan()) { // Encode a NaN. sign_bit = 0; significand = HMath::raise(2, significand_bits) - 1; exponent = HMath::raise(2, exp_bits) - 1; } else if (val.isZero()) { // Encode a basic 0. sign_bit = 0; significand = 0; exponent = 0; } else { // Regular input value. sign_bit = val.isNegative() ? 1 : 0; // Determine exponent. HNumber search_min = min_exp; HNumber search_max = max_exp; exponent = HMath::ceil((search_max - search_min) / 2) + search_min; significand = HMath::abs(val) * HMath::raise(2, -exponent); do { if (significand >= 1 && significand < 2) { // Integer part is 1, stop here. break; } else if (significand >= 2) { // Increase exponent. search_min = exponent + 1; } else if (significand < 1) { // Decrease exponent. search_max = exponent - 1; } exponent = HMath::ceil((search_max - search_min) / 2) + search_min; significand = HMath::abs(val) * HMath::raise(2, -exponent); } while (exponent != min_exp && exponent != max_exp); HNumber rounded = HMath::round(significand * HMath::raise(2, significand_bits)); HNumber intpart = HMath::integer(rounded * HMath::raise(2, -significand_bits)); significand = HMath::mask(rounded, significand_bits); if (intpart.isZero()) { // Subnormal value. exponent = 0; } else if (intpart > 1) { // Infinity. exponent = HMath::raise(2, exp_bits) - 1; significand = 0; } else { // Normalised value. exponent = exponent + exp_bias; } } HNumber result = sign_bit << (exp_bits + significand_bits) | exponent << (significand_bits) | significand; return result; } std::ostream& operator<<(std::ostream& s, const HNumber& n) { QString str = HMath::format(n); s << str.toLatin1().constData(); return s; } struct MathInit { MathInit(){ floatmath_init(); } }; MathInit mathinit; /** * Parses a string containing a real number. * * Parameters : * str_in : pointer towards the string to parse * str_out : pointer towards a pointer towards the remaining of the string after parsing */ HNumber HMath::parse_str(const char* str_in, const char** str_out) { // FIXME: Duplicate code. // FIXME: Error management. const char* str = str_in; t_itokens tokens; HNumber x; delete x.d; x.d = new HNumberPrivate; if ((x.d->error = parse(&tokens, &str)) == Success) x.d->error = float_in(&x.d->fnum, &tokens); float_geterror(); /* Store remaining of the string */ if (str_out) *str_out = str; return x; } bool HNumber::isNearZero() const { return float_iszero(&(d->fnum)) || float_getexponent(&(d->fnum)) <= -80; } deepin-calculator-1.0.2/math/hmath.h000066400000000000000000000201141325241207700173110ustar00rootroot00000000000000// HMath: C++ high precision math routines // Copyright (C) 2004 Ariya Hidayat // Copyright (C) 2007-2008, 2014, 2016 @heldercorreia // Copyright (C) 2008 Wolf Lammen // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef MATH_HMATH_H #define MATH_HMATH_H #include "core/errors.h" #include #include #include class HMath; class HNumberPrivate; class CNumber; class CMath; class Rational; class HNumber { friend class HMath; friend class CNumber; friend class CMath; friend HNumber operator-(const HNumber&); friend HNumber operator-(const HNumber&, const HNumber&); friend bool operator>(const HNumber&, const HNumber&); friend bool operator<(const HNumber&, const HNumber&); friend bool operator>=(const HNumber&, const HNumber&); friend bool operator<=(const HNumber&, const HNumber&); friend bool operator==(const HNumber&, const HNumber&); friend bool operator!=(const HNumber&, const HNumber&); public: HNumber(); HNumber(const HNumber&); HNumber(int); HNumber(const char*); HNumber(const QJsonObject&); ~HNumber(); bool isNan() const; bool isZero() const; bool isNearZero() const; bool isPositive() const; bool isNegative() const; bool isInteger() const; void serialize(QJsonObject&) const; static HNumber deSerialize(const QJsonObject&); int toInt() const; Error error() const; HNumber& operator=(const HNumber&); HNumber operator+(const HNumber&) const; HNumber& operator+=(const HNumber&); HNumber& operator-=(const HNumber&); HNumber operator*(const HNumber&) const; HNumber& operator*=(const HNumber&); HNumber operator/(const HNumber&) const; HNumber& operator/=(const HNumber&); HNumber operator%(const HNumber&) const; HNumber operator&(const HNumber&) const; HNumber& operator&=(const HNumber&); HNumber operator|(const HNumber&) const; HNumber& operator|=(const HNumber&); HNumber operator^(const HNumber&) const; HNumber& operator^=(const HNumber&); HNumber operator~() const; HNumber operator>>(const HNumber&) const; HNumber operator<<(const HNumber&) const; private: HNumberPrivate* d; int compare(const HNumber&) const; public: struct Format { enum class Base {Null, Binary, Decimal, Octal, Hexadecimal}; enum class RadixChar {Null, Point, Comma}; enum class Mode {Null, General, Fixed, Scientific, Engineering}; Base base; RadixChar radixChar; Mode mode; int precision; // -1 means 'auto' static const int PrecisionNull = -1000; Format(); Format(const Format&); Format operator+(const Format&) const; static Format Binary(); static Format Octal(); static Format Decimal(); static Format Hexadecimal(); static Format Precision(int); static Format Point(); static Format Comma(); static Format General(); static Format Fixed(); static Format Scientific(); static Format Engineering(); }; }; class HMath { public: // FORMAT static QString format(const HNumber&, HNumber::Format = HNumber::Format()); // PARSING static HNumber parse_str(const char*, const char** out); // CONSTANTS static HNumber e(); static HNumber phi(); static HNumber pi(); static HNumber nan(Error = Success); // GENERAL MATH static HNumber rad2deg(const HNumber&); static HNumber deg2rad(const HNumber&); static HNumber max(const HNumber&, const HNumber&); static HNumber min(const HNumber&, const HNumber&); static HNumber abs(const HNumber&); static HNumber integer(const HNumber&); static HNumber frac(const HNumber&); static HNumber floor(const HNumber&); static HNumber ceil(const HNumber&); static HNumber gcd(const HNumber&, const HNumber&); static HNumber idiv(const HNumber&, const HNumber&); static HNumber round(const HNumber&, int prec = 0); static HNumber trunc(const HNumber&, int prec = 0); static HNumber sqrt(const HNumber&); static HNumber cbrt(const HNumber&); static HNumber raise(const HNumber&, int); static HNumber raise(const HNumber&, const HNumber&); static HNumber sgn(const HNumber&); // EXPONENTIAL FUNCTION AND RELATED static HNumber exp(const HNumber&); static HNumber ln(const HNumber&); static HNumber lg(const HNumber&); static HNumber lb(const HNumber&); static HNumber log(const HNumber& base, const HNumber& x); static HNumber sinh(const HNumber&); static HNumber cosh(const HNumber&); static HNumber tanh(const HNumber&); static HNumber arsinh(const HNumber&); static HNumber arcosh(const HNumber&); static HNumber artanh(const HNumber&); // TRIGONOMETRY static HNumber sin(const HNumber&); static HNumber cos(const HNumber&); static HNumber tan(const HNumber&); static HNumber cot(const HNumber&); static HNumber sec(const HNumber&); static HNumber csc(const HNumber&); static HNumber arcsin(const HNumber&); static HNumber arccos(const HNumber&); static HNumber arctan(const HNumber&); static HNumber arctan2(const HNumber&, const HNumber&); // HIGHER MATH FUNCTIONS static HNumber factorial(const HNumber&, const HNumber& base = HNumber(1)); static HNumber gamma(const HNumber&); static HNumber lnGamma(const HNumber&); static HNumber erf(const HNumber&); static HNumber erfc(const HNumber&); // PROBABILITY static HNumber nCr(const HNumber& n, const HNumber& k); static HNumber nPr(const HNumber& n, const HNumber& r); static HNumber binomialPmf(const HNumber& k, const HNumber& n, const HNumber& p); static HNumber binomialCdf(const HNumber& k, const HNumber& n, const HNumber& p); static HNumber binomialMean(const HNumber& n, const HNumber& p); static HNumber binomialVariance(const HNumber& n, const HNumber& p); static HNumber hypergeometricPmf(const HNumber& k, const HNumber& N, const HNumber& M, const HNumber& n); static HNumber hypergeometricCdf(const HNumber& k, const HNumber& N, const HNumber& M, const HNumber& n); static HNumber hypergeometricMean(const HNumber& N, const HNumber& M, const HNumber& n); static HNumber hypergeometricVariance(const HNumber& N, const HNumber& M, const HNumber& n); static HNumber poissonPmf(const HNumber& k, const HNumber& l); static HNumber poissonCdf(const HNumber& k, const HNumber& l); static HNumber poissonMean(const HNumber& l); static HNumber poissonVariance(const HNumber& l); // LOGIC static HNumber mask(const HNumber&, const HNumber& bits); static HNumber sgnext(const HNumber&, const HNumber& bits); static HNumber ashr(const HNumber&, const HNumber& bits); // IEEE-754 CONVERSION static HNumber decodeIeee754(const HNumber&, const HNumber& exp_bits, const HNumber& significand_bits); static HNumber decodeIeee754(const HNumber&, const HNumber& exp_bits, const HNumber& significand_bits, const HNumber& exp_bias); static HNumber encodeIeee754(const HNumber&, const HNumber& exp_bits, const HNumber& significand_bits); static HNumber encodeIeee754(const HNumber&, const HNumber& exp_bits, const HNumber& significand_bits, const HNumber& exp_bias); }; std::ostream& operator<<(std::ostream&, const HNumber&); #endif // MATH_HMATH_H deepin-calculator-1.0.2/math/number.c000066400000000000000000001226271325241207700175070ustar00rootroot00000000000000/* number.c: Implements arbitrary precision numbers. */ /* Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc. 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 2 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; see the file COPYING. If not, write to: The Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA. You may contact the author by: e-mail: philnelson@acm.org us-mail: Philip A. Nelson Computer Science Department, 9062 Western Washington University Bellingham, WA 98226-9062 !!!This is a patched file, the original file from bc 1.06 contains bugs in (a) bc_divide and (b) bc_int2num. A patch is applied here by Wolf Lammen, Oertzweg 45, 22307 Hamburg email ookami1 gmx de One patched line fixes a nasty bug, where a division by 1 may fail occasionly when an operand is overwritten by the result. The other one lets a conversion of an integer succeed, even if the most negative integer is passed as argument *************************************************************************/ #include "number.h" #include #include #include #include #include /* Prototypes needed for external utility routines. */ #define bc_rt_warn rt_warn #define bc_rt_error rt_error #define bc_out_of_memory out_of_memory _PROTOTYPE(void rt_warn, (char *mesg ,...)); _PROTOTYPE(void rt_error, (char *mesg ,...)); _PROTOTYPE(void out_of_memory, (void)); void out_of_memory(void){ return; } void rt_warn(char *mesg ,...){ (void)mesg; return; } void rt_error(char *mesg ,...){ (void)mesg; return; } /* Storage used for special numbers. */ bc_num _zero_; bc_num _one_; bc_num _two_; static bc_num _bc_Free_list = NULL; /* new_num allocates a number and sets fields to known values. */ bc_num bc_new_num (length, scale) int length, scale; { bc_num temp; if (_bc_Free_list != NULL) { temp = _bc_Free_list; _bc_Free_list = temp->n_next; } else { temp = (bc_num) malloc (sizeof(bc_struct)); if (temp == NULL) bc_out_of_memory (); } temp->n_sign = PLUS; temp->n_len = length; temp->n_scale = scale; temp->n_refs = 1; temp->n_ptr = (char *) malloc (length+scale+1); if (temp->n_ptr == NULL) bc_out_of_memory(); temp->n_value = temp->n_ptr; memset (temp->n_ptr, 0, length+scale); return temp; } /* "Frees" a bc_num NUM. Actually decreases reference count and only frees the storage if reference count is zero. */ void bc_free_num (num) bc_num *num; { if (*num == NULL) return; (*num)->n_refs--; if ((*num)->n_refs == 0) { if ((*num)->n_ptr) free ((*num)->n_ptr); (*num)->n_next = _bc_Free_list; _bc_Free_list = *num; } *num = NULL; } /* Intitialize the number package! */ void bc_init_numbers () { _zero_ = bc_new_num (1,0); _one_ = bc_new_num (1,0); _one_->n_value[0] = 1; _two_ = bc_new_num (1,0); _two_->n_value[0] = 2; } /* Make a copy of a number! Just increments the reference count! */ bc_num bc_copy_num (num) bc_num num; { num->n_refs++; return num; } /* Initialize a number NUM by making it a copy of zero. */ void bc_init_num (num) bc_num *num; { *num = bc_copy_num (_zero_); } /* For many things, we may have leading zeros in a number NUM. _bc_rm_leading_zeros just moves the data "value" pointer to the correct place and adjusts the length. */ static void _bc_rm_leading_zeros (num) bc_num num; { /* We can move n_value to point to the first non zero digit! */ while (*num->n_value == 0 && num->n_len > 1) { num->n_value++; num->n_len--; } } /* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just compare the magnitudes. */ static int _bc_do_compare (n1, n2, use_sign, ignore_last) bc_num n1, n2; int use_sign; int ignore_last; { char *n1ptr, *n2ptr; int count; /* First, compare signs. */ if (use_sign && n1->n_sign != n2->n_sign) { if (n1->n_sign == PLUS) return (1); /* Positive N1 > Negative N2 */ else return (-1); /* Negative N1 < Positive N1 */ } /* Now compare the magnitude. */ if (n1->n_len != n2->n_len) { if (n1->n_len > n2->n_len) { /* Magnitude of n1 > n2. */ if (!use_sign || n1->n_sign == PLUS) return (1); else return (-1); } else { /* Magnitude of n1 < n2. */ if (!use_sign || n1->n_sign == PLUS) return (-1); else return (1); } } /* If we get here, they have the same number of integer digits. check the integer part and the equal length part of the fraction. */ count = n1->n_len + MIN (n1->n_scale, n2->n_scale); n1ptr = n1->n_value; n2ptr = n2->n_value; while ((count > 0) && (*n1ptr == *n2ptr)) { n1ptr++; n2ptr++; count--; } if (ignore_last && count == 1 && n1->n_scale == n2->n_scale) return (0); if (count != 0) { if (*n1ptr > *n2ptr) { /* Magnitude of n1 > n2. */ if (!use_sign || n1->n_sign == PLUS) return (1); else return (-1); } else { /* Magnitude of n1 < n2. */ if (!use_sign || n1->n_sign == PLUS) return (-1); else return (1); } } /* They are equal up to the last part of the equal part of the fraction. */ if (n1->n_scale != n2->n_scale) { if (n1->n_scale > n2->n_scale) { for (count = n1->n_scale-n2->n_scale; count>0; count--) if (*n1ptr++ != 0) { /* Magnitude of n1 > n2. */ if (!use_sign || n1->n_sign == PLUS) return (1); else return (-1); } } else { for (count = n2->n_scale-n1->n_scale; count>0; count--) if (*n2ptr++ != 0) { /* Magnitude of n1 < n2. */ if (!use_sign || n1->n_sign == PLUS) return (-1); else return (1); } } } /* They must be equal! */ return (0); } /* This is the "user callable" routine to compare numbers N1 and N2. */ int bc_compare (n1, n2) bc_num n1, n2; { return _bc_do_compare (n1, n2, TRUE, FALSE); } /* In some places we need to check if the number is negative. */ char bc_is_neg (num) bc_num num; { return num->n_sign == MINUS; } /* In some places we need to check if the number NUM is zero. */ char bc_is_zero (num) bc_num num; { int count; char *nptr; /* Quick check. */ if (num == _zero_) return TRUE; /* Initialize */ count = num->n_len + num->n_scale; nptr = num->n_value; /* The check */ while ((count > 0) && (*nptr++ == 0)) count--; if (count != 0) return FALSE; else return TRUE; } /* In some places we need to check if the number NUM is almost zero. Specifically, all but the last digit is 0 and the last digit is 1. Last digit is defined by scale. */ char bc_is_near_zero (num, scale) bc_num num; int scale; { int count; char *nptr; /* Error checking */ if (scale > num->n_scale) scale = num->n_scale; /* Initialize */ count = num->n_len + scale; nptr = num->n_value; /* The check */ while ((count > 0) && (*nptr++ == 0)) count--; if (count != 0 && (count != 1 || *--nptr != 1)) return FALSE; else return TRUE; } /* Perform addition: N1 is added to N2 and the value is returned. The signs of N1 and N2 are ignored. SCALE_MIN is to set the minimum scale of the result. */ static bc_num _bc_do_add (n1, n2, scale_min) bc_num n1, n2; int scale_min; { bc_num sum; int sum_scale, sum_digits; char *n1ptr, *n2ptr, *sumptr; int carry, n1bytes, n2bytes; int count; /* Prepare sum. */ sum_scale = MAX (n1->n_scale, n2->n_scale); sum_digits = MAX (n1->n_len, n2->n_len) + 1; sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min)); /* Zero extra digits made by scale_min. */ if (scale_min > sum_scale) { sumptr = (char *) (sum->n_value + sum_scale + sum_digits); for (count = scale_min - sum_scale; count > 0; count--) *sumptr++ = 0; } /* Start with the fraction part. Initialize the pointers. */ n1bytes = n1->n_scale; n2bytes = n2->n_scale; n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1); n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1); sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1); /* Add the fraction part. First copy the longer fraction.*/ if (n1bytes != n2bytes) { if (n1bytes > n2bytes) while (n1bytes>n2bytes) { *sumptr-- = *n1ptr--; n1bytes--;} else while (n2bytes>n1bytes) { *sumptr-- = *n2ptr--; n2bytes--;} } /* Now add the remaining fraction part and equal size integer parts. */ n1bytes += n1->n_len; n2bytes += n2->n_len; carry = 0; while ((n1bytes > 0) && (n2bytes > 0)) { *sumptr = *n1ptr-- + *n2ptr-- + carry; if (*sumptr > (BASE-1)) { carry = 1; *sumptr -= BASE; } else carry = 0; sumptr--; n1bytes--; n2bytes--; } /* Now add carry the longer integer part. */ if (n1bytes == 0) { n1bytes = n2bytes; n1ptr = n2ptr; } while (n1bytes-- > 0) { *sumptr = *n1ptr-- + carry; if (*sumptr > (BASE-1)) { carry = 1; *sumptr -= BASE; } else carry = 0; sumptr--; } /* Set final carry. */ if (carry == 1) *sumptr += 1; /* Adjust sum and return. */ _bc_rm_leading_zeros (sum); return sum; } /* Perform subtraction: N2 is subtracted from N1 and the value is returned. The signs of N1 and N2 are ignored. Also, N1 is assumed to be larger than N2. SCALE_MIN is the minimum scale of the result. */ static bc_num _bc_do_sub (n1, n2, scale_min) bc_num n1, n2; int scale_min; { bc_num diff; int diff_scale, diff_len; int min_scale, min_len; char *n1ptr, *n2ptr, *diffptr; int borrow, count, val; /* Allocate temporary storage. */ diff_len = MAX (n1->n_len, n2->n_len); diff_scale = MAX (n1->n_scale, n2->n_scale); min_len = MIN (n1->n_len, n2->n_len); min_scale = MIN (n1->n_scale, n2->n_scale); diff = bc_new_num (diff_len, MAX(diff_scale, scale_min)); /* Zero extra digits made by scale_min. */ if (scale_min > diff_scale) { diffptr = (char *) (diff->n_value + diff_len + diff_scale); for (count = scale_min - diff_scale; count > 0; count--) *diffptr++ = 0; } /* Initialize the subtract. */ n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1); n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1); diffptr = (char *) (diff->n_value + diff_len + diff_scale -1); /* Subtract the numbers. */ borrow = 0; /* Take care of the longer scaled number. */ if (n1->n_scale != min_scale) { /* n1 has the longer scale */ for (count = n1->n_scale - min_scale; count > 0; count--) *diffptr-- = *n1ptr--; } else { /* n2 has the longer scale */ for (count = n2->n_scale - min_scale; count > 0; count--) { val = - *n2ptr-- - borrow; if (val < 0) { val += BASE; borrow = 1; } else borrow = 0; *diffptr-- = val; } } /* Now do the equal length scale and integer parts. */ for (count = 0; count < min_len + min_scale; count++) { val = *n1ptr-- - *n2ptr-- - borrow; if (val < 0) { val += BASE; borrow = 1; } else borrow = 0; *diffptr-- = val; } /* If n1 has more digits then n2, we now do that subtract. */ if (diff_len != min_len) { for (count = diff_len - min_len; count > 0; count--) { val = *n1ptr-- - borrow; if (val < 0) { val += BASE; borrow = 1; } else borrow = 0; *diffptr-- = val; } } /* Clean up and return. */ _bc_rm_leading_zeros (diff); return diff; } /* Here is the full subtract routine that takes care of negative numbers. N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN is the minimum scale for the result. */ void bc_sub (n1, n2, result, scale_min) bc_num n1, n2, *result; int scale_min; { bc_num diff = NULL; int cmp_res; int res_scale; if (n1->n_sign != n2->n_sign) { diff = _bc_do_add (n1, n2, scale_min); diff->n_sign = n1->n_sign; } else { /* subtraction must be done. */ /* Compare magnitudes. */ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); switch (cmp_res) { case -1: /* n1 is less than n2, subtract n1 from n2. */ diff = _bc_do_sub (n2, n1, scale_min); diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS); break; case 0: /* They are equal! return zero! */ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); diff = bc_new_num (1, res_scale); memset (diff->n_value, 0, res_scale+1); break; case 1: /* n2 is less than n1, subtract n2 from n1. */ diff = _bc_do_sub (n1, n2, scale_min); diff->n_sign = n1->n_sign; break; } } /* Clean up and return. */ bc_free_num (result); *result = diff; } /* Here is the full add routine that takes care of negative numbers. N1 is added to N2 and the result placed into RESULT. SCALE_MIN is the minimum scale for the result. */ void bc_add (n1, n2, result, scale_min) bc_num n1, n2, *result; int scale_min; { bc_num sum = NULL; int cmp_res; int res_scale; if (n1->n_sign == n2->n_sign) { sum = _bc_do_add (n1, n2, scale_min); sum->n_sign = n1->n_sign; } else { /* subtraction must be done. */ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ switch (cmp_res) { case -1: /* n1 is less than n2, subtract n1 from n2. */ sum = _bc_do_sub (n2, n1, scale_min); sum->n_sign = n2->n_sign; break; case 0: /* They are equal! return zero with the correct scale! */ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); sum = bc_new_num (1, res_scale); memset (sum->n_value, 0, res_scale+1); break; case 1: /* n2 is less than n1, subtract n2 from n1. */ sum = _bc_do_sub (n1, n2, scale_min); sum->n_sign = n1->n_sign; } } /* Clean up and return. */ bc_free_num (result); *result = sum; } /* Recursive vs non-recursive multiply crossover ranges. */ #if defined(MULDIGITS) #include "muldigits.h" #else #define MUL_BASE_DIGITS 80 #endif int mul_base_digits = MUL_BASE_DIGITS; #define MUL_SMALL_DIGITS mul_base_digits/4 /* Multiply utility routines */ static bc_num new_sub_num (length, scale, value) int length, scale; char *value; { bc_num temp; if (_bc_Free_list != NULL) { temp = _bc_Free_list; _bc_Free_list = temp->n_next; } else { temp = (bc_num) malloc (sizeof(bc_struct)); if (temp == NULL) bc_out_of_memory (); } temp->n_sign = PLUS; temp->n_len = length; temp->n_scale = scale; temp->n_refs = 1; temp->n_ptr = NULL; temp->n_value = value; return temp; } static void _bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod, int full_scale) { char *n1ptr, *n2ptr, *pvptr; char *n1end, *n2end; /* To the end of n1 and n2. */ int indx, sum; const int prodlen = n1len + n2len + 1; (void)full_scale; *prod = bc_new_num (prodlen, 0); n1end = (char *) (n1->n_value + n1len - 1); n2end = (char *) (n2->n_value + n2len - 1); pvptr = (char *) ((*prod)->n_value + prodlen - 1); sum = 0; /* Here is the loop... */ for (indx = 0; indx < prodlen-1; indx++) { n1ptr = (char *) (n1end - MAX(0, indx-n2len+1)); n2ptr = (char *) (n2end - MIN(indx, n2len-1)); while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) sum += *n1ptr-- * *n2ptr++; *pvptr-- = sum % BASE; sum = sum / BASE; } *pvptr = sum; } /* A special adder/subtractor for the recursive divide and conquer multiply algorithm. Note: if sub is called, accum must be larger that what is being subtracted. Also, accum and val must have n_scale = 0. (e.g. they must look like integers. *) */ static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub) { signed char *accp, *valp; int count, carry; count = val->n_len; if (val->n_value[0] == 0) count--; assert (accum->n_len+accum->n_scale >= shift+count); /* Set up pointers and others */ accp = (signed char *)(accum->n_value + accum->n_len + accum->n_scale - shift - 1); valp = (signed char *)(val->n_value + val->n_len - 1); carry = 0; if (sub) { /* Subtraction, carry is really borrow. */ while (count--) { *accp -= *valp-- + carry; if (*accp < 0) { carry = 1; *accp-- += BASE; } else { carry = 0; accp--; } } while (carry) { *accp -= carry; if (*accp < 0) *accp-- += BASE; else carry = 0; } } else { /* Addition */ while (count--) { *accp += *valp-- + carry; if (*accp > (BASE-1)) { carry = 1; *accp-- -= BASE; } else { carry = 0; accp--; } } while (carry) { *accp += carry; if (*accp > (BASE-1)) *accp-- -= BASE; else carry = 0; } } } /* Recursive divide and conquer multiply algorithm. Based on Let u = u0 + u1*(b^n) Let v = v0 + v1*(b^n) Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0 B is the base of storage, number of digits in u1,u0 close to equal. */ static void _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod, int full_scale) { bc_num u0, u1, v0, v1; /*int u0len, v0len;*/ bc_num m1, m2, m3, d1, d2; int n, prodlen, m1zero; int d1len, d2len; /* Base case? */ if ((ulen+vlen) < mul_base_digits || ulen < MUL_SMALL_DIGITS || vlen < MUL_SMALL_DIGITS ) { _bc_simp_mul (u, ulen, v, vlen, prod, full_scale); return; } /* Calculate n -- the u and v split point in digits. */ n = (MAX(ulen, vlen)+1) / 2; /* Split u and v. */ if (ulen < n) { u1 = bc_copy_num (_zero_); u0 = new_sub_num (ulen,0, u->n_value); } else { u1 = new_sub_num (ulen-n, 0, u->n_value); u0 = new_sub_num (n, 0, u->n_value+ulen-n); } if (vlen < n) { v1 = bc_copy_num (_zero_); v0 = new_sub_num (vlen,0, v->n_value); } else { v1 = new_sub_num (vlen-n, 0, v->n_value); v0 = new_sub_num (n, 0, v->n_value+vlen-n); } _bc_rm_leading_zeros (u1); _bc_rm_leading_zeros (u0); /*u0len = u0->n_len;*/ _bc_rm_leading_zeros (v1); _bc_rm_leading_zeros (v0); /*v0len = v0->n_len;*/ m1zero = bc_is_zero(u1) || bc_is_zero(v1); /* Calculate sub results ... */ bc_init_num(&d1); bc_init_num(&d2); bc_sub (u1, u0, &d1, 0); d1len = d1->n_len; bc_sub (v0, v1, &d2, 0); d2len = d2->n_len; /* Do recursive multiplies and shifted adds. */ if (m1zero) m1 = bc_copy_num (_zero_); else _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0); if (bc_is_zero(d1) || bc_is_zero(d2)) m2 = bc_copy_num (_zero_); else _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0); if (bc_is_zero(u0) || bc_is_zero(v0)) m3 = bc_copy_num (_zero_); else _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0); /* Initialize product */ prodlen = ulen+vlen+1; *prod = bc_new_num(prodlen, 0); if (!m1zero) { _bc_shift_addsub (*prod, m1, 2*n, 0); _bc_shift_addsub (*prod, m1, n, 0); } _bc_shift_addsub (*prod, m3, n, 0); _bc_shift_addsub (*prod, m3, 0, 0); _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign); /* Now clean up! */ bc_free_num (&u1); bc_free_num (&u0); bc_free_num (&v1); bc_free_num (&m1); bc_free_num (&v0); bc_free_num (&m2); bc_free_num (&m3); bc_free_num (&d1); bc_free_num (&d2); } /* The multiply routine. N2 times N1 is put int PROD with the scale of the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). */ void bc_multiply (n1, n2, prod, scale) bc_num n1, n2, *prod; int scale; { bc_num pval; int len1, len2; int full_scale, prod_scale; /* Initialize things. */ len1 = n1->n_len + n1->n_scale; len2 = n2->n_len + n2->n_scale; full_scale = n1->n_scale + n2->n_scale; prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale))); /* Do the multiply */ _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale); /* Assign to prod and clean up the number. */ pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); pval->n_value = pval->n_ptr; pval->n_len = len2 + len1 + 1 - full_scale; pval->n_scale = prod_scale; _bc_rm_leading_zeros (pval); if (bc_is_zero (pval)) pval->n_sign = PLUS; bc_free_num (prod); *prod = pval; } /* Some utility routines for the divide: First a one digit multiply. NUM (with SIZE digits) is multiplied by DIGIT and the result is placed into RESULT. It is written so that NUM and RESULT can be the same pointers. */ static void _one_mult (num, size, digit, result) unsigned char *num; int size, digit; unsigned char *result; { int carry, value; unsigned char *nptr, *rptr; if (digit == 0) memset (result, 0, size); else { if (digit == 1) memcpy (result, num, size); else { /* Initialize */ nptr = (unsigned char *) (num+size-1); rptr = (unsigned char *) (result+size-1); carry = 0; while (size-- > 0) { value = *nptr-- * digit + carry; *rptr-- = value % BASE; carry = value / BASE; } if (carry != 0) *rptr = carry; } } } /* The full division routine. This computes N1 / N2. It returns 0 if the division is ok and the result is in QUOT. The number of digits after the decimal point is SCALE. It returns -1 if division by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ int bc_divide (n1, n2, quot, scale) bc_num n1, n2, *quot; int scale; { bc_num qval; unsigned char *num1, *num2; unsigned char *ptr1, *ptr2, *n2ptr, *qptr; int scale1, val; unsigned int len1, len2, scale2, qdigits, extra, count; unsigned int qdig, qguess, borrow, carry; unsigned char *mval; char zero; unsigned int norm; /* Test for divide by zero. */ if (bc_is_zero (n2)) return -1; /* Test for divide by 1. If it is we must truncate. */ if (n2->n_scale == 0) { if (n2->n_len == 1 && *n2->n_value == 1) { qval = bc_new_num (n1->n_len, scale); qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); memset (&qval->n_value[n1->n_len],0,scale); memcpy (qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale,scale)); bc_free_num (quot); *quot = qval; return 0; /* bug fix Wolf Lammen */ } } /* Set up the divide. Move the decimal point on n1 by n2's scale. Remember, zeros on the end of num2 are wasted effort for dividing. */ scale2 = n2->n_scale; n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1; while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--; len1 = n1->n_len + scale2; scale1 = n1->n_scale - scale2; if (scale1 < scale) extra = scale - scale1; else extra = 0; num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2); if (num1 == NULL) bc_out_of_memory(); memset (num1, 0, n1->n_len+n1->n_scale+extra+2); memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale); len2 = n2->n_len + scale2; num2 = (unsigned char *) malloc (len2+1); if (num2 == NULL) bc_out_of_memory(); memcpy (num2, n2->n_value, len2); *(num2+len2) = 0; n2ptr = num2; while (*n2ptr == 0) { n2ptr++; len2--; } /* Calculate the number of quotient digits. */ if (len2 > len1+scale) { qdigits = scale+1; zero = TRUE; } else { zero = FALSE; if (len2>len1) qdigits = scale+1; /* One for the zero integer part. */ else qdigits = len1-len2+scale+1; } /* Allocate and zero the storage for the quotient. */ qval = bc_new_num (qdigits-scale,scale); memset (qval->n_value, 0, qdigits); /* Allocate storage for the temporary storage mval. */ mval = (unsigned char *) malloc (len2+1); if (mval == NULL) bc_out_of_memory (); /* Now for the full divide algorithm. */ if (!zero) { /* Normalize */ norm = 10 / ((int)*n2ptr + 1); if (norm != 1) { _one_mult (num1, len1+scale1+extra+1, norm, num1); _one_mult (n2ptr, len2, norm, n2ptr); } /* Initialize divide loop. */ qdig = 0; if (len2 > len1) qptr = (unsigned char *) qval->n_value+len2-len1; else qptr = (unsigned char *) qval->n_value; /* Loop */ while (qdig <= len1+scale-len2) { /* Calculate the quotient digit guess. */ if (*n2ptr == num1[qdig]) qguess = 9; else qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr; /* Test qguess. */ if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) { qguess--; /* And again. */ if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) qguess--; } /* Multiply and subtract. */ borrow = 0; if (qguess != 0) { *mval = 0; _one_mult (n2ptr, len2, qguess, mval+1); ptr1 = (unsigned char *) num1+qdig+len2; ptr2 = (unsigned char *) mval+len2; for (count = 0; count < len2+1; count++) { val = (int) *ptr1 - (int) *ptr2-- - borrow; if (val < 0) { val += 10; borrow = 1; } else borrow = 0; *ptr1-- = val; } } /* Test for negative result. */ if (borrow == 1) { qguess--; ptr1 = (unsigned char *) num1+qdig+len2; ptr2 = (unsigned char *) n2ptr+len2-1; carry = 0; for (count = 0; count < len2; count++) { val = (int) *ptr1 + (int) *ptr2-- + carry; if (val > 9) { val -= 10; carry = 1; } else carry = 0; *ptr1-- = val; } if (carry == 1) *ptr1 = (*ptr1 + 1) % 10; } /* We now know the quotient digit. */ *qptr++ = qguess; qdig++; } } /* Clean up and return the number. */ qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); if (bc_is_zero (qval)) qval->n_sign = PLUS; _bc_rm_leading_zeros (qval); bc_free_num (quot); *quot = qval; /* Clean up temporary storage. */ free (mval); free (num1); free (num2); return 0; /* Everything is OK. */ } /* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT is NULL then that store will be omitted. */ int bc_divmod (num1, num2, quot, rem, scale) bc_num num1, num2, *quot, *rem; int scale; { bc_num quotient = NULL; bc_num temp; int rscale; /* Check for correct numbers. */ if (bc_is_zero (num2)) return -1; /* Calculate final scale. */ rscale = MAX (num1->n_scale, num2->n_scale+scale); bc_init_num(&temp); /* Calculate it. */ bc_divide (num1, num2, &temp, scale); if (quot) quotient = bc_copy_num (temp); bc_multiply (temp, num2, &temp, rscale); bc_sub (num1, temp, rem, rscale); bc_free_num (&temp); if (quot) { bc_free_num (quot); *quot = quotient; } return 0; /* Everything is OK. */ } /* Modulo for numbers. This computes NUM1 % NUM2 and puts the result in RESULT. */ int bc_modulo (num1, num2, result, scale) bc_num num1, num2, *result; int scale; { return bc_divmod (num1, num2, NULL, result, scale); } /* Raise BASE to the EXPO power, reduced modulo MOD. The result is placed in RESULT. If a EXPO is not an integer, only the integer part is used. */ int bc_raisemod (base, expo, mod, result, scale) bc_num base, expo, mod, *result; int scale; { bc_num power, exponent, parity, temp; int rscale; /* Check for correct numbers. */ if (bc_is_zero(mod)) return -1; if (bc_is_neg(expo)) return -1; /* Set initial values. */ power = bc_copy_num (base); exponent = bc_copy_num (expo); temp = bc_copy_num (_one_); bc_init_num(&parity); /* Check the base for scale digits. */ if (base->n_scale != 0) bc_rt_warn ("non-zero scale in base"); /* Check the exponent for scale digits. */ if (exponent->n_scale != 0) { bc_rt_warn ("non-zero scale in exponent"); bc_divide (exponent, _one_, &exponent, 0); /*truncate */ } /* Check the modulus for scale digits. */ if (mod->n_scale != 0) bc_rt_warn ("non-zero scale in modulus"); /* Do the calculation. */ rscale = MAX(scale, base->n_scale); while ( !bc_is_zero(exponent) ) { (void) bc_divmod (exponent, _two_, &exponent, &parity, 0); if ( !bc_is_zero(parity) ) { bc_multiply (temp, power, &temp, rscale); (void) bc_modulo (temp, mod, &temp, scale); } bc_multiply (power, power, &power, rscale); (void) bc_modulo (power, mod, &power, scale); } /* Assign the value. */ bc_free_num (&power); bc_free_num (&exponent); bc_free_num (result); *result = temp; return 0; /* Everything is OK. */ } /* Raise NUM1 to the NUM2 power. The result is placed in RESULT. Maximum exponent is LONG_MAX. If a NUM2 is not an integer, only the integer part is used. */ void bc_raise (num1, num2, result, scale) bc_num num1, num2, *result; int scale; { bc_num temp, power; long exponent; int rscale; int pwrscale; int calcscale; char neg; /* Check the exponent for scale digits and convert to a long. */ if (num2->n_scale != 0) bc_rt_warn ("non-zero scale in exponent"); exponent = bc_num2long (num2); if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) bc_rt_error ("exponent too large in raise"); /* Special case if exponent is a zero. */ if (exponent == 0) { bc_free_num (result); *result = bc_copy_num (_one_); return; } /* Other initializations. */ if (exponent < 0) { neg = TRUE; exponent = -exponent; rscale = scale; } else { neg = FALSE; rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale)); } /* Set initial value of temp. */ power = bc_copy_num (num1); pwrscale = num1->n_scale; while ((exponent & 1) == 0) { pwrscale = 2*pwrscale; bc_multiply (power, power, &power, pwrscale); exponent = exponent >> 1; } temp = bc_copy_num (power); calcscale = pwrscale; exponent = exponent >> 1; /* Do the calculation. */ while (exponent > 0) { pwrscale = 2*pwrscale; bc_multiply (power, power, &power, pwrscale); if ((exponent & 1) == 1) { calcscale = pwrscale + calcscale; bc_multiply (temp, power, &temp, calcscale); } exponent = exponent >> 1; } /* Assign the value. */ if (neg) { bc_divide (_one_, temp, result, rscale); bc_free_num (&temp); } else { bc_free_num (result); *result = temp; if ((*result)->n_scale > rscale) (*result)->n_scale = rscale; } bc_free_num (&power); } /* Take the square root NUM and return it in NUM with SCALE digits after the decimal place. */ int bc_sqrt (num, scale) bc_num *num; int scale; { int rscale, cmp_res, done; int cscale; bc_num guess, guess1, point5, diff; /* Initial checks. */ cmp_res = bc_compare (*num, _zero_); if (cmp_res < 0) return 0; /* error */ else { if (cmp_res == 0) { bc_free_num (num); *num = bc_copy_num (_zero_); return 1; } } cmp_res = bc_compare (*num, _one_); if (cmp_res == 0) { bc_free_num (num); *num = bc_copy_num (_one_); return 1; } /* Initialize the variables. */ rscale = MAX (scale, (*num)->n_scale); bc_init_num(&guess); bc_init_num(&guess1); bc_init_num(&diff); point5 = bc_new_num (1,1); point5->n_value[1] = 5; /* Calculate the initial guess. */ if (cmp_res < 0) { /* The number is between 0 and 1. Guess should start at 1. */ guess = bc_copy_num (_one_); cscale = (*num)->n_scale; } else { /* The number is greater than 1. Guess should start at 10^(exp/2). */ bc_int2num (&guess,10); bc_int2num (&guess1,(*num)->n_len); bc_multiply (guess1, point5, &guess1, 0); guess1->n_scale = 0; bc_raise (guess, guess1, &guess, 0); bc_free_num (&guess1); cscale = 3; } /* Find the square root using Newton's algorithm. */ done = FALSE; while (!done) { bc_free_num (&guess1); guess1 = bc_copy_num (guess); bc_divide (*num, guess, &guess, cscale); bc_add (guess, guess1, &guess, 0); bc_multiply (guess, point5, &guess, cscale); bc_sub (guess, guess1, &diff, cscale+1); if (bc_is_near_zero (diff, cscale)) { if (cscale < rscale+1) cscale = MIN (cscale*3, rscale+1); else done = TRUE; } } /* Assign the number and clean up. */ bc_free_num (num); bc_divide (guess,_one_,num,rscale); bc_free_num (&guess); bc_free_num (&guess1); bc_free_num (&point5); bc_free_num (&diff); return 1; } /* The following routines provide output for bcd numbers package using the rules of POSIX bc for output. */ /* This structure is used for saving digits in the conversion process. */ typedef struct stk_rec { long digit; struct stk_rec *next; } stk_rec; /* The reference string for digits. */ static char ref_str[] = "0123456789ABCDEF"; /* A special output routine for "multi-character digits." Exactly SIZE characters must be output for the value VAL. If SPACE is non-zero, we must output one space before the number. OUT_CHAR is the actual routine for writing the characters. */ void bc_out_long (val, size, space, out_char) long val; int size, space; #ifdef NUMBER__STDC__ void (*out_char)(int); #else void (*out_char)(); #endif { char digits[40]; int len, ix; if (space) (*out_char) (' '); sprintf (digits, "%ld", val); len = strlen (digits); while (size > len) { (*out_char) ('0'); size--; } for (ix=0; ix < len; ix++) (*out_char) (digits[ix]); } /* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR as the routine to do the actual output of the characters. */ void bc_out_num (num, o_base, out_char, leading_zero) bc_num num; int o_base; #ifdef NUMBER__STDC__ void (*out_char)(int); #else void (*out_char)(); #endif int leading_zero; { char *nptr; int index, fdigit, pre_space; stk_rec *digits, *temp; bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit; /* The negative sign if needed. */ if (num->n_sign == MINUS) (*out_char) ('-'); /* Output the number. */ if (bc_is_zero (num)) (*out_char) ('0'); else if (o_base == 10) { /* The number is in base 10, do it the fast way. */ nptr = num->n_value; if (num->n_len > 1 || *nptr != 0) for (index=num->n_len; index>0; index--) (*out_char) (BCD_CHAR(*nptr++)); else nptr++; if (leading_zero && bc_is_zero (num)) (*out_char) ('0'); /* Now the fraction. */ if (num->n_scale > 0) { (*out_char) ('.'); for (index=0; indexn_scale; index++) (*out_char) (BCD_CHAR(*nptr++)); } } else { /* special case ... */ if (leading_zero && bc_is_zero (num)) (*out_char) ('0'); /* The number is some other base. */ digits = NULL; bc_init_num (&int_part); bc_divide (num, _one_, &int_part, 0); bc_init_num (&frac_part); bc_init_num (&cur_dig); bc_init_num (&base); bc_sub (num, int_part, &frac_part, 0); /* Make the INT_PART and FRAC_PART positive. */ int_part->n_sign = PLUS; frac_part->n_sign = PLUS; bc_int2num (&base, o_base); bc_init_num (&max_o_digit); bc_int2num (&max_o_digit, o_base-1); /* Get the digits of the integer part and push them on a stack. */ while (!bc_is_zero (int_part)) { bc_modulo (int_part, base, &cur_dig, 0); temp = (stk_rec *) malloc (sizeof(stk_rec)); if (temp == NULL) bc_out_of_memory(); temp->digit = bc_num2long (cur_dig); temp->next = digits; digits = temp; bc_divide (int_part, base, &int_part, 0); } /* Print the digits on the stack. */ if (digits != NULL) { /* Output the digits. */ while (digits != NULL) { temp = digits; digits = digits->next; if (o_base <= 16) (*out_char) (ref_str[ (int) temp->digit]); else bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char); free (temp); } } /* Get and print the digits of the fraction part. */ if (num->n_scale > 0) { (*out_char) ('.'); pre_space = 0; t_num = bc_copy_num (_one_); while (t_num->n_len <= num->n_scale) { bc_multiply (frac_part, base, &frac_part, num->n_scale); fdigit = bc_num2long (frac_part); bc_int2num (&int_part, fdigit); bc_sub (frac_part, int_part, &frac_part, 0); if (o_base <= 16) (*out_char) (ref_str[fdigit]); else { bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char); pre_space = 1; } bc_multiply (t_num, base, &t_num, 0); } bc_free_num (&t_num); } /* Clean up. */ bc_free_num (&int_part); bc_free_num (&frac_part); bc_free_num (&base); bc_free_num (&cur_dig); bc_free_num (&max_o_digit); } } /* Convert a number NUM to a long. The function returns only the integer part of the number. For numbers that are too large to represent as a long, this function returns a zero. This can be detected by checking the NUM for zero after having a zero returned. */ long bc_num2long (num) bc_num num; { long val; char *nptr; int index; /* Extract the int value, ignore the fraction. */ val = 0; nptr = num->n_value; for (index=num->n_len; (index>0) && (val<=(LONG_MAX/BASE)); index--) val = val*BASE + *nptr++; /* Check for overflow. If overflow, return zero. */ if (index>0) val = 0; if (val < 0) val = 0; /* Return the value. */ if (num->n_sign == PLUS) return (val); else return (-val); } /* Convert an integer VAL to a bc number NUM. */ void bc_int2num (num, val) bc_num *num; int val; { char buffer[30]; char *bptr, *vptr; int ix = 1; char neg = 0; /* Sign. */ if (val < 0) { neg = 1; val = -val; } /* Get things going. */ bptr = buffer; *bptr++ = (unsigned)val % BASE; /* type cast to unsigned, bug fix Wolf Lammen */ val = (unsigned)val / BASE; /* type cast to unsigned, bug fix Wolf Lammen */ /* Extract remaining digits. */ while (val != 0) { *bptr++ = val % BASE; val = val / BASE; ix++; /* Count the digits. */ } /* Make the number. */ bc_free_num (num); *num = bc_new_num (ix, 0); if (neg) (*num)->n_sign = MINUS; /* Assign the digits. */ vptr = (*num)->n_value; while (ix-- > 0) *vptr++ = *--bptr; } /* Convert a numbers to a string. Base 10 only.*/ char *bc_num2str (num) bc_num num; { char *str, *sptr; char *nptr; int index, signch; /* Allocate the string memory. */ signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */ if (num->n_scale > 0) str = (char *) malloc (num->n_len + num->n_scale + 2 + signch); else str = (char *) malloc (num->n_len + 1 + signch); if (str == NULL) bc_out_of_memory(); /* The negative sign if needed. */ sptr = str; if (signch) *sptr++ = '-'; /* Load the whole number. */ nptr = num->n_value; for (index=num->n_len; index>0; index--) *sptr++ = BCD_CHAR(*nptr++); /* Now the fraction. */ if (num->n_scale > 0) { *sptr++ = '.'; for (index=0; indexn_scale; index++) *sptr++ = BCD_CHAR(*nptr++); } /* Terminate the string and return it! */ *sptr = '\0'; return (str); } /* Convert strings to bc numbers. Base 10 only.*/ void bc_str2num (num, str, scale) bc_num *num; char *str; int scale; { int digits, strscale; char *ptr, *nptr; char zero_int; /* Prepare num. */ bc_free_num (num); /* Check for valid number and count digits. */ ptr = str; digits = 0; strscale = 0; zero_int = FALSE; if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */ while (*ptr == '0') ptr++; /* Skip leading zeros. */ while (isdigit((int)*ptr)) ptr++, digits++; /* digits */ if (*ptr == '.') ptr++; /* decimal point */ while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */ if ((*ptr != '\0') || (digits+strscale == 0)) { *num = bc_copy_num (_zero_); return; } /* Adjust numbers and allocate storage and initialize fields. */ strscale = MIN(strscale, scale); if (digits == 0) { zero_int = TRUE; digits = 1; } *num = bc_new_num (digits, strscale); /* Build the whole number. */ ptr = str; if (*ptr == '-') { (*num)->n_sign = MINUS; ptr++; } else { (*num)->n_sign = PLUS; if (*ptr == '+') ptr++; } while (*ptr == '0') ptr++; /* Skip leading zeros. */ nptr = (*num)->n_value; if (zero_int) { *nptr++ = 0; digits = 0; } for (;digits > 0; digits--) *nptr++ = CH_VAL(*ptr++); /* Build the fractional part. */ if (strscale > 0) { ptr++; /* skip the decimal point! */ for (;strscale > 0; strscale--) *nptr++ = CH_VAL(*ptr++); } } /* pn prints the number NUM in base 10. */ static void out_char (int c) { putchar(c); } void pn (num) bc_num num; { bc_out_num (num, 10, out_char, 0); out_char ('\n'); } /* pv prints a character array as if it was a string of bcd digits. */ void pv (name, num, len) char *name; unsigned char *num; int len; { int i; printf ("%s=", name); for (i=0; i #ifdef __cplusplus extern "C" { #endif #undef _PROTOTYPE #ifndef NUMBER__STDC__ #define NUMBER__STDC__ #endif typedef enum {PLUS, MINUS} sign; typedef struct bc_struct *bc_num; typedef struct bc_struct { sign n_sign; int n_len; /* The number of digits before the decimal point. */ int n_scale; /* The number of digits after the decimal point. */ int n_refs; /* The number of pointers to this number. */ bc_num n_next; /* Linked list for available list. */ char *n_ptr; /* The pointer to the actual storage. If NULL, n_value points to the inside of another number (bc_multiply...) and should not be "freed." */ char *n_value; /* The number. Not zero char terminated. May not point to the same place as n_ptr as in the case of leading zeros generated. */ } bc_struct; /* The base used in storing the numbers in n_value above. Currently this MUST be 10. */ #define BASE 10 /* Some useful macros and constants. */ #define CH_VAL(c) (c - '0') #define CH_HEX(c) ((c < ':') ? ( c - '0') : (c < 'G') ? ( c - 'A' + 10) : ( c - 'a' + 10)) #define BCD_CHAR(d) (d + '0') #ifdef MIN #undef MIN #undef MAX #endif #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)>(b)?(b):(a)) #define ODD(a) ((a)&1) #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef LONG_MAX #define LONG_MAX 0x7ffffff #endif /* Global numbers. */ extern bc_num _zero_; extern bc_num _one_; extern bc_num _two_; /* Function Prototypes */ /* Define the _PROTOTYPE macro if it is needed. */ #ifndef _PROTOTYPE #ifdef NUMBER__STDC__ #define _PROTOTYPE(func, args) func args #else #define _PROTOTYPE(func, args) func() #endif #endif _PROTOTYPE(void bc_init_numbers, (void)); _PROTOTYPE(bc_num bc_new_num, (int length, int scale)); _PROTOTYPE(void bc_free_num, (bc_num *num)); _PROTOTYPE(bc_num bc_copy_num, (bc_num num)); _PROTOTYPE(void bc_init_num, (bc_num *num)); _PROTOTYPE(void bc_str2num, (bc_num *num, char *str, int scale)); _PROTOTYPE(char *bc_num2str, (bc_num num)); _PROTOTYPE(void bc_int2num, (bc_num *num, int val)); _PROTOTYPE(long bc_num2long, (bc_num num)); _PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2)); _PROTOTYPE(char bc_is_zero, (bc_num num)); _PROTOTYPE(char bc_is_near_zero, (bc_num num, int scale)); _PROTOTYPE(char bc_is_neg, (bc_num num)); _PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); _PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); _PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale)); _PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale)); _PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result, int scale)); _PROTOTYPE(int bc_divmod, (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale)); _PROTOTYPE(int bc_raisemod, (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)); _PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result, int scale)); _PROTOTYPE(int bc_sqrt, (bc_num *num, int scale)); _PROTOTYPE(void bc_out_num, (bc_num num, int o_base, void (* out_char)(int), int leading_zero)); #ifdef __cplusplus } #endif #endif deepin-calculator-1.0.2/math/quantity.cpp000066400000000000000000000611031325241207700204240ustar00rootroot00000000000000// quantity.cpp // Support for units and dimensions // // This file is part of the SpeedCrunch project // Copyright (C) 2016 Pol Welter. // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "quantity.h" #include "rational.h" #include "units.h" #include #define RATIONAL_TOL HNumber("1e-20") #define ENSURE_DIMENSIONLESS(x) \ if (!(x).isDimensionless()) \ return DMath::nan(InvalidDimension); #define ENSURE_SAME_DIMENSION(x, y) \ if ((!(x).sameDimension(y))) \ return DMath::nan(DimensionMismatch); Quantity operator-(const Quantity& q) { Quantity res(q); res.m_numericValue = -res.m_numericValue; return res; } Quantity operator-(const Quantity& a, const Quantity& b) { Quantity res(a); if (!a.sameDimension(b)) return DMath::nan(DimensionMismatch); res.m_numericValue -= b.m_numericValue; return res; } bool operator>(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue > r.m_numericValue; return false; } bool operator<(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue < r.m_numericValue; return false; } bool operator>=(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue >= r.m_numericValue; return false; } bool operator<=(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue <= r.m_numericValue; return false; } bool operator==(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue == r.m_numericValue; return false; } // Returns TRUE upon dimension mismatch. bool operator!=(const Quantity& l, const Quantity& r) { if (l.sameDimension(r)) return l.m_numericValue != r.m_numericValue; return true; } Quantity operator*(const HNumber& l, const Quantity& r) { return r * l; } Quantity operator*(const CNumber& l, const Quantity& r) { return r * l; } Quantity operator/(const HNumber& l, const Quantity& r) { return Quantity(l) / r; } Quantity operator/(const CNumber& l, const Quantity& r) { return Quantity(l) / r; } Quantity::Quantity() : m_numericValue(0) , m_unit(nullptr) , m_unitName("") { } Quantity::Quantity(const Quantity& other) : m_numericValue(other.m_numericValue) , m_dimension(other.m_dimension) , m_unit(nullptr) , m_unitName(other.m_unitName) , m_format(other.m_format) { if (other.hasUnit()) this->m_unit = new CNumber(other.unit()); cleanDimension(); } Quantity::Quantity(int i) : Quantity(CNumber(i)) { } Quantity::Quantity(const QJsonObject& json) : Quantity() { *this = deSerialize(json); } Quantity::Quantity(const HNumber& h) : Quantity(CNumber(h)) { } Quantity::Quantity(const CNumber& c) : Quantity() { this->m_numericValue = c; } Quantity::~Quantity() { delete m_unit; } bool Quantity::isNan() const { return m_numericValue.isNan(); } bool Quantity::isZero() const { return m_numericValue.isZero(); } bool Quantity::isReal() const { return m_numericValue.isReal(); } bool Quantity::isPositive() const { return m_numericValue.isPositive(); } bool Quantity::isNegative() const { return m_numericValue.isNegative(); } bool Quantity::isInteger() const { return (!this->hasDimension() && !this->hasUnit()) && m_numericValue.isInteger(); } bool Quantity::hasUnit() const { return this->m_unit != NULL; } CNumber Quantity::unit() const { if (this->hasUnit()) return CNumber(*(this->m_unit)); return CNumber(1); } QString Quantity::unitName() const { if (this->hasUnit()) return m_unitName; return ""; } CNumber Quantity::numericValue() const { return m_numericValue; } Quantity& Quantity::setDisplayUnit(const CNumber unit, const QString& name) { if (unit.isNan()) *this = DMath::nan(InvalidDimension); else { stripUnits(); m_unit = new CNumber(unit); m_unitName = name; } return *this; } Quantity& Quantity::setFormat(Format c) { m_format = c; return *this; } void Quantity::stripUnits() { delete m_unit; m_unit = nullptr; m_unitName = ""; } bool Quantity::hasDimension() const { return !this->m_dimension.empty(); } /* * Unlike hasDimension(), this does a clean up first, i.e. it * checks for redundant exponents. */ bool Quantity::isDimensionless() const { Quantity temp(*this); temp.cleanDimension(); return m_dimension.empty(); } QMap Quantity::getDimension() const { Quantity temp(*this); temp.cleanDimension(); return temp.m_dimension; } void Quantity::modifyDimension(const QString& key, const Rational& exponent) { if (exponent.isZero()) m_dimension.remove(key); else m_dimension.insert(key, exponent); } void Quantity::copyDimension(const Quantity& other) { clearDimension(); this->m_dimension = other.m_dimension; } void Quantity::clearDimension() { this->m_dimension.clear(); } // Note: Does NOT clean the dimension vector first. // The calling function must do so on its own. bool Quantity::sameDimension(const Quantity& other) const { return this->m_dimension == other.m_dimension; } void Quantity::cleanDimension() { auto i = m_dimension.begin(); while (i != m_dimension.end()) { if (i.value().isZero()) i = m_dimension.erase(i); else ++i; } } void Quantity::serialize(QJsonObject& json) const { QJsonObject nom_json; m_numericValue.serialize(nom_json); json["numeric_value"] = nom_json; if (hasDimension()) { QJsonObject dim_json; auto i = m_dimension.constBegin(); while (i != m_dimension.constEnd()) { const auto& exp = i.value(); const auto& name = i.key(); dim_json[name] = exp.toString(); ++i; } json["dimension"] = dim_json; } if (hasUnit()) { QJsonObject unit_json; m_unit->serialize(unit_json); json["unit"] = unit_json; json["unit_name"] = m_unitName; } if (!m_format.isNull()) { QJsonObject format_json; m_format.serialize(format_json); json["format"] = format_json; } } Quantity Quantity::deSerialize(const QJsonObject& json) { Quantity result; if (json.contains("numeric_value")) { QJsonObject num_json = json["numeric_value"].toObject(); result.m_numericValue = CNumber(num_json); } result.stripUnits(); if (json.contains("unit")) { QJsonObject unit_json = json["unit"].toObject(); result.m_unit = new CNumber(unit_json); } if (json.contains("unit_name")) result.m_unitName = json["unit_name"].toString(); if (json.contains("dimension")) { QJsonObject dim_json = json["dimension"].toObject(); for (int i = 0; i < dim_json.count(); ++i) { auto key = dim_json.keys()[i]; Rational val(dim_json[key].toString()); result.modifyDimension(key, val); } } if (json.contains("format")) { QJsonObject format_json = json["format"].toObject(); result.m_format = Quantity::Format::deSerialize(format_json); } return result; } Error Quantity::error() const { return m_numericValue.error(); } Quantity& Quantity::operator=(const Quantity& other) { m_numericValue = other.m_numericValue; m_dimension = other.m_dimension; m_format = other.m_format; stripUnits(); if(other.hasUnit()) { m_unit = new CNumber(*other.m_unit); m_unitName = other.m_unitName; } cleanDimension(); return *this; } Quantity Quantity::operator+(const Quantity& other) const { if (!this->sameDimension(other)) return DMath::nan(DimensionMismatch); Quantity result(*this); result.m_numericValue += other.m_numericValue; return result; } Quantity& Quantity::operator+=(const Quantity& other) { if (!this->sameDimension(other)) *this = DMath::nan(DimensionMismatch); else this->m_numericValue += other.m_numericValue; return *this; } Quantity& Quantity::operator-=(const Quantity& other) { return operator=(*this - other); } Quantity Quantity::operator*(const Quantity& other) const { Quantity result(*this); result.m_numericValue *= other.m_numericValue; if (!other.isDimensionless()) { result.stripUnits(); auto i = other.m_dimension.constBegin(); while (i != other.m_dimension.constEnd()) { const auto& exp = i.value(); const auto& name = i.key(); if (!result.m_dimension.contains(name)) result.m_dimension[name] = Rational(0); result.m_dimension[name] += exp; ++i; } result.cleanDimension(); } return result; } Quantity Quantity::operator*(const CNumber& other) const { Quantity result(*this); result.m_numericValue *= other; return result; } Quantity Quantity::operator*(const HNumber& other) const { return operator*(CNumber(other)); } Quantity &Quantity::operator*=(const Quantity& other) { return operator=(*this * other); } Quantity Quantity::operator/(const Quantity& other) const { Quantity result(*this); result.m_numericValue /= other.m_numericValue; if (!other.isDimensionless()) { result.stripUnits(); auto i = other.m_dimension.constBegin(); while (i != other.m_dimension.constEnd()) { const auto& exp = i.value(); const auto& name = i.key(); if (!result.m_dimension.contains(name)) result.m_dimension[name] = Rational(0); result.m_dimension[name] -= exp; ++i; } result.cleanDimension(); } return result; } Quantity Quantity::operator/(const HNumber& other) const { return operator/(CNumber(other)); } Quantity Quantity::operator/(const CNumber& other) const { Quantity result(*this); result.m_numericValue /= other; result.cleanDimension(); return result; } Quantity &Quantity::operator/=(const Quantity& other) { return operator=(*this/other); } Quantity Quantity::operator%(const Quantity& other) const { Quantity result(*this); result.m_numericValue = result.m_numericValue % other.m_numericValue; return result; } Quantity Quantity::operator&(const Quantity& other) const { ENSURE_DIMENSIONLESS(*this); ENSURE_DIMENSIONLESS(other); Quantity result(*this); result.m_numericValue &= other.m_numericValue; return result; } Quantity &Quantity::operator&=(const Quantity& other) { return operator=(*this & other); } Quantity Quantity::operator|(const Quantity& other) const { ENSURE_DIMENSIONLESS(*this); ENSURE_DIMENSIONLESS(other); Quantity result(*this); result.m_numericValue |= other.m_numericValue; return result; } Quantity &Quantity::operator|=(const Quantity& other) { return operator=(*this | other); } Quantity Quantity::operator^(const Quantity& other) const { ENSURE_DIMENSIONLESS(*this); ENSURE_DIMENSIONLESS(other); Quantity result(*this); result.m_numericValue ^= other.m_numericValue; return result; } Quantity &Quantity::operator^=(const Quantity& other) { return operator=(*this ^ other); } Quantity Quantity::operator~() const { ENSURE_DIMENSIONLESS(*this); Quantity result(*this); result.m_numericValue= ~result.m_numericValue; return result; } Quantity Quantity::operator>>(const Quantity& other) const { ENSURE_DIMENSIONLESS(*this); ENSURE_DIMENSIONLESS(other); Quantity result(*this); result.m_numericValue = result.m_numericValue >> other.m_numericValue; return result; } Quantity Quantity::operator<<(const Quantity& other) const { ENSURE_DIMENSIONLESS(*this); ENSURE_DIMENSIONLESS(other); Quantity result(*this); result.m_numericValue = result.m_numericValue << other.m_numericValue; return result; } Quantity::Format::Format() : CNumber::Format() { } Quantity::Format::Format(const CNumber::Format& other) : CNumber::Format(other) { } Quantity::Format::Format(const HNumber::Format& other) : CNumber::Format(other) { } Quantity::Format Quantity::Format::operator+(const Quantity::Format& other) const { return Quantity::Format(CNumber::Format::operator+(static_cast(other))); } void Quantity::Format::serialize(QJsonObject& json) const { switch (mode) { case Mode::General: json["mode"] = QStringLiteral("General"); break; case Mode::Fixed: json["mode"] = QStringLiteral("Fixed"); break; case Mode::Scientific: json["mode"] = QStringLiteral("Scientific"); break; case Mode::Engineering: json["mode"] = QStringLiteral("Engineering"); break; case Mode::Null: break; } switch (base) { case Base::Binary: json["base"] = QStringLiteral("Binary"); break; case Base::Octal: json["base"] = QStringLiteral("Octal"); break; case Base::Hexadecimal: json["base"] = QStringLiteral("Hexadecimal"); break; case Base::Decimal: json["base"] = QStringLiteral("Decimal"); break; case Base::Null: break; } switch (notation) { case Notation::Cartesian: json["form"] = QStringLiteral("Cartesian"); break; case Notation::Polar: json["form"] = QStringLiteral("Polar"); break; case Notation::Null: default: break; } if (precision != PrecisionNull) json["precision"] = precision; } Quantity::Format Quantity::Format::deSerialize(const QJsonObject& json) { Format result; if (json.contains("mode")) { auto strMode = json["mode"].toString(); if (strMode == "General") result.mode = Mode::General; else if (strMode == "Fixed") result.mode = Mode::Fixed; else if (strMode == "Scientific") result.mode = Mode::Scientific; else if (strMode == "Engineering") result.mode = Mode::Engineering; else result.mode = Mode::Null; } else result.mode = Mode::Null; if (json.contains("base")) { auto strBase = json["base"].toString(); if (strBase == "Binary") result.base = Base::Binary; else if (strBase == "Octal") result.base = Base::Octal; else if (strBase == "Decimal") result.base = Base::Decimal; else if (strBase == "Hexadecimal") result.base = Base::Hexadecimal; else result.base = Base::Null; } else result.base = Base::Null; if (json.contains("form")) { auto strNotation = json["form"].toString(); if (strNotation == "Cartesian") result.notation = Notation::Cartesian; else if (strNotation == "Polar") result.notation = Notation::Polar; else result.notation = Notation::Null; } else result.notation = Notation::Null; result.precision = json.contains("precision") ? json["precision"].toInt() : PrecisionNull; return result; } bool Quantity::Format::isNull() const { return (mode == Mode::Null && base == Base::Null && precision == PrecisionNull && notation == Notation::Null); } // DMath // ===== bool DMath::complexMode = true; #define COMPLEX_WRAP_1(fct, arg) \ (DMath::complexMode ? CMath::fct(arg) : CNumber(HMath::fct(arg.real))) #define COMPLEX_WRAP_2(fct, arg1, arg2) \ (DMath::complexMode ? CMath::fct(arg1, arg2) : CNumber(HMath::fct(arg1.real, arg2.real))) #define COMPLEX_WRAP_3(fct, arg1, arg2, arg3) \ (DMath::complexMode ? CMath::fct(arg1, arg2, arg3) : CNumber(HMath::fct(arg1.real, arg2.real, arg3.real))) #define COMPLEX_WRAP_4(fct, arg1, arg2, arg3, arg4) \ (DMath::complexMode ? CMath::fct(arg1, arg2, arg3, arg4) \ : CNumber(HMath::fct(arg1.real, arg2.real, arg3.real, arg4.real))) // Wrappers for functions that are only defined for dimensionless arguments // Mo argument. #define WRAPPER_DMATH_0(fct) \ Quantity DMath::fct() \ { \ return Quantity(CMath::fct()); \ } \ // One argument. #define WRAPPER_DMATH_1(fct) \ Quantity DMath::fct(const Quantity& arg1) \ { \ ENSURE_DIMENSIONLESS(arg1); \ return Quantity(COMPLEX_WRAP_1(fct, arg1.m_numericValue)); \ } // Two arguments. #define WRAPPER_DMATH_2(fct) \ Quantity DMath::fct(const Quantity& arg1, const Quantity& arg2) \ { \ ENSURE_DIMENSIONLESS(arg1); \ ENSURE_DIMENSIONLESS(arg2); \ return Quantity(COMPLEX_WRAP_2(fct, arg1.m_numericValue, arg2.m_numericValue)); \ } // Three arguments. #define WRAPPER_DMATH_3(fct) \ Quantity DMath::fct(const Quantity& arg1, const Quantity& arg2, const Quantity& arg3) \ { \ ENSURE_DIMENSIONLESS(arg1); \ ENSURE_DIMENSIONLESS(arg2); \ ENSURE_DIMENSIONLESS(arg3); \ return Quantity(COMPLEX_WRAP_3(fct, arg1.m_numericValue, arg2.m_numericValue, arg3.m_numericValue)); \ } // Four arguments. #define WRAPPER_DMATH_4(fct) \ Quantity DMath::fct(const Quantity& arg1, const Quantity& arg2, const Quantity& arg3, const Quantity& arg4) \ { \ ENSURE_DIMENSIONLESS(arg1); \ ENSURE_DIMENSIONLESS(arg2); \ ENSURE_DIMENSIONLESS(arg3); \ ENSURE_DIMENSIONLESS(arg4); \ return Quantity(COMPLEX_WRAP_4(fct, arg1.m_numericValue, arg2.m_numericValue, arg3.m_numericValue, \ arg4.m_numericValue)); \ } WRAPPER_DMATH_0(e) WRAPPER_DMATH_0(pi) WRAPPER_DMATH_0(phi) WRAPPER_DMATH_0(i) Quantity DMath::nan(Error error) { return Quantity(CMath::nan(error)); } WRAPPER_DMATH_1(rad2deg) WRAPPER_DMATH_1(deg2rad) WRAPPER_DMATH_1(integer) WRAPPER_DMATH_1(frac) WRAPPER_DMATH_1(floor) WRAPPER_DMATH_1(ceil) WRAPPER_DMATH_1(exp) WRAPPER_DMATH_1(ln) WRAPPER_DMATH_1(lg) WRAPPER_DMATH_1(lb) WRAPPER_DMATH_2(log) WRAPPER_DMATH_1(sinh) WRAPPER_DMATH_1(cosh) WRAPPER_DMATH_1(tanh) WRAPPER_DMATH_1(arsinh) WRAPPER_DMATH_1(arcosh) WRAPPER_DMATH_1(artanh) WRAPPER_DMATH_1(sin) WRAPPER_DMATH_1(cos) WRAPPER_DMATH_1(tan) WRAPPER_DMATH_1(cot) WRAPPER_DMATH_1(sec) WRAPPER_DMATH_1(csc) WRAPPER_DMATH_1(arcsin) WRAPPER_DMATH_1(arccos) WRAPPER_DMATH_1(arctan) WRAPPER_DMATH_2(arctan2) WRAPPER_DMATH_2(factorial) WRAPPER_DMATH_1(gamma) WRAPPER_DMATH_1(lnGamma) WRAPPER_DMATH_1(erf) WRAPPER_DMATH_1(erfc) WRAPPER_DMATH_2(gcd) WRAPPER_DMATH_2(idiv) Quantity DMath::round(const Quantity& n, int prec) { ENSURE_DIMENSIONLESS(n); return DMath::complexMode ? CMath::round(n.numericValue(), prec) : CNumber(HMath::round(n.numericValue().real, prec)); } Quantity DMath::trunc(const Quantity& n, int prec) { ENSURE_DIMENSIONLESS(n); return DMath::complexMode ? CMath::trunc(n.numericValue(), prec) : CNumber(HMath::trunc(n.numericValue().real, prec)); } WRAPPER_DMATH_2(nCr) WRAPPER_DMATH_2(nPr) WRAPPER_DMATH_3(binomialPmf) WRAPPER_DMATH_3(binomialCdf) WRAPPER_DMATH_2(binomialMean) WRAPPER_DMATH_2(binomialVariance) WRAPPER_DMATH_4(hypergeometricPmf) WRAPPER_DMATH_4(hypergeometricCdf) WRAPPER_DMATH_3(hypergeometricMean) WRAPPER_DMATH_3(hypergeometricVariance) WRAPPER_DMATH_2(poissonPmf) WRAPPER_DMATH_2(poissonCdf) WRAPPER_DMATH_1(poissonMean) WRAPPER_DMATH_1(poissonVariance) WRAPPER_DMATH_2(mask) WRAPPER_DMATH_2(sgnext) WRAPPER_DMATH_2(ashr) WRAPPER_DMATH_3(decodeIeee754) WRAPPER_DMATH_4(decodeIeee754) QString DMath::format(Quantity q, Quantity::Format format) { format = q.format() + format; // Left hand side oerator takes priority. // Handle units. if (!q.hasUnit() && !q.isDimensionless()) { q.cleanDimension(); Units::findUnit(q); } QString unit_name = ' ' + q.unitName(); CNumber unit = q.unit(); CNumber number = q.m_numericValue; number /= unit; QString result = CMath::format(number, format); // rekols mark. // TODO: add thousands separators. if (!number.real.isZero() && !number.imag.isZero() && unit_name != " ") result = "(" + result + ")"; if (unit_name != " ") result.append(unit_name); return result; } Quantity DMath::real(const Quantity& x) { Quantity result(x); result.m_numericValue = result.m_numericValue.real; return result; } Quantity DMath::imag(const Quantity& x) { Quantity result(x); result.m_numericValue = result.m_numericValue.imag; return result; } Quantity DMath::abs(const Quantity& n) { Quantity result(n); result.m_numericValue = COMPLEX_WRAP_1(abs, n.m_numericValue); return result; } Quantity DMath::phase(const Quantity& n) { return CMath::phase(n.numericValue()); } Quantity DMath::sqrt(const Quantity& n) { Quantity result(COMPLEX_WRAP_1(sqrt, n.m_numericValue)); auto i = n.m_dimension.constBegin(); while (i != n.m_dimension.constEnd()) { auto& exp = i.value(); auto& name = i.key(); result.modifyDimension(name, exp * Rational(1,2)); ++i; } return result; } Quantity DMath::cbrt(const Quantity& n) { Quantity result(COMPLEX_WRAP_1(cbrt, n.m_numericValue)); auto i = n.m_dimension.constBegin(); while (i != n.m_dimension.constEnd()) { auto& exp = i.value(); auto& name = i.key(); result.modifyDimension(name, exp * Rational(1,3)); ++i; } return result; } Quantity DMath::raise(const Quantity& n1, int n) { Quantity result; result.m_numericValue = complexMode ? CMath::raise(n1.m_numericValue, n) : CNumber(HMath::raise(n1.m_numericValue.real, n)); auto i = n1.m_dimension.constBegin(); while (i != n1.m_dimension.constEnd()) { auto& exp = i.value(); auto& name = i.key(); result.modifyDimension(name, exp * n); ++i; } return result; } Quantity DMath::raise(const Quantity& n1, const Quantity& n2) { if (!n2.isDimensionless() || (!n1.isDimensionless() && !n2.isReal() && complexMode)) return DMath::nan(InvalidDimension); // First get the new numeric value. Quantity result(COMPLEX_WRAP_2(raise, n1.m_numericValue, n2.m_numericValue)); if (n1.isDimensionless()) return result; // We can now assume that n1 has a dimension, but n2 is real. // Compute the new dimension: try to convert n2 to a Rational. If n2 is not // rational, return NaN. // For negative bases only allow odd denominators. Rational exponent(n2.m_numericValue.real); if (abs(exponent.toHNumber() - n2.m_numericValue.real) >= RATIONAL_TOL || (n1.isNegative() && exponent.denominator() % 2 == 0)) return DMath::nan(OutOfDomain); // Compute new dimension. auto i = n1.m_dimension.constBegin(); while (i != n1.m_dimension.constEnd()) { result.modifyDimension(i.key(), i.value()*exponent); ++i; } return result; } Quantity DMath::sgn(const Quantity& x) { return Quantity(CMath::sgn(x.m_numericValue)); } Quantity DMath::encodeIeee754(const Quantity& val, const Quantity& exp_bits, const Quantity& significand_bits) { ENSURE_DIMENSIONLESS(val); ENSURE_DIMENSIONLESS(exp_bits); ENSURE_DIMENSIONLESS(significand_bits); Quantity result(CMath::encodeIeee754(val.numericValue(), exp_bits.numericValue(), significand_bits.numericValue())); result.m_format = result.m_format + Quantity::Format::Fixed() + Quantity::Format::Hexadecimal(); return result; } Quantity DMath::encodeIeee754(const Quantity& val, const Quantity& exp_bits, const Quantity& significand_bits, const Quantity& exp_bias) { ENSURE_DIMENSIONLESS(val); ENSURE_DIMENSIONLESS(exp_bits); ENSURE_DIMENSIONLESS(significand_bits); ENSURE_DIMENSIONLESS(exp_bias); Quantity result(CMath::encodeIeee754(val.numericValue(), exp_bits.numericValue(), significand_bits.numericValue(), exp_bias.numericValue())); result.m_format = result.m_format + Quantity::Format::Fixed() + Quantity::Format::Hexadecimal(); return result; } deepin-calculator-1.0.2/math/quantity.h000066400000000000000000000215071325241207700200750ustar00rootroot00000000000000// quantity.h // Support for units and dimensions // // This file is part of the SpeedCrunch project // Copyright (C) 2016 Pol Welter. // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef QUANTITY_H #define QUANTITY_H #include "cmath.h" #include "hmath.h" #include "core/errors.h" #include class CNumber; class HNumber; class QJsonObject; class QString; class Rational; class DMath; class Quantity; Quantity operator*(const HNumber&, const Quantity&); Quantity operator*(const CNumber&, const Quantity&); Quantity operator/(const HNumber&, const Quantity&); Quantity operator/(const CNumber&, const Quantity&); class Quantity { friend class DMath; friend Quantity operator-(const Quantity&); friend Quantity operator-(const Quantity&, const Quantity&); friend bool operator>(const Quantity&, const Quantity&); friend bool operator<(const Quantity&, const Quantity&); friend bool operator>=(const Quantity&, const Quantity&); friend bool operator<=(const Quantity&, const Quantity&); friend bool operator==(const Quantity&, const Quantity&); friend bool operator!=(const Quantity&, const Quantity&); public: Quantity(); Quantity(const Quantity&); Quantity(int); Quantity(const QJsonObject&); Quantity(const HNumber&); Quantity(const CNumber&); ~Quantity(); bool isNan() const; bool isZero() const; bool isReal() const; bool isPositive() const; bool isNegative() const; bool isInteger() const; bool hasUnit() const; CNumber unit() const; QString unitName() const; CNumber numericValue() const; Quantity& setDisplayUnit(const CNumber unit, const QString& name); void stripUnits(); bool hasDimension() const; bool isDimensionless() const; QMap getDimension() const; void modifyDimension(const QString& key, const Rational& exponent); void copyDimension(const Quantity&); void clearDimension(); bool sameDimension(const Quantity& other) const; void cleanDimension(); void serialize(QJsonObject&) const; static Quantity deSerialize(const QJsonObject&); Error error() const; Quantity& operator=(const Quantity&); Quantity operator+(const Quantity&) const; Quantity& operator+=(const Quantity&); Quantity& operator-=(const Quantity&); Quantity operator*(const Quantity&) const; Quantity operator*(const CNumber&) const; Quantity operator*(const HNumber&) const; Quantity& operator*=(const Quantity&); Quantity operator/(const Quantity&) const; Quantity operator/(const HNumber&) const; Quantity operator/(const CNumber&) const; Quantity& operator/=(const Quantity&); Quantity operator%(const Quantity&) const; Quantity operator&(const Quantity&) const; Quantity& operator&=(const Quantity&); Quantity operator|(const Quantity&) const; Quantity& operator|=(const Quantity&); Quantity operator^(const Quantity&) const; Quantity& operator^=(const Quantity&); Quantity operator~() const; Quantity operator>>(const Quantity&) const; Quantity operator<<(const Quantity&) const; class Format : public CNumber::Format { public: Format(); Format(const CNumber::Format&); Format(const HNumber::Format&); Format operator+(const Format&) const; void serialize(QJsonObject&) const; static Format deSerialize(const QJsonObject&); bool isNull() const; }; Format format() const { return m_format; } Quantity& setFormat(Format); private: CNumber m_numericValue; QMap m_dimension; CNumber* m_unit; QString m_unitName; Format m_format; }; /* * Math functions for quantities with dimensions */ class DMath { public: static bool complexMode; static QString format(const Quantity, Quantity::Format = Quantity::Format()); // CONSTANTS static Quantity e(); static Quantity phi(); static Quantity pi(); static Quantity nan(Error = Success); static Quantity i(); // GENERAL MATH static Quantity rad2deg(const Quantity&); static Quantity deg2rad(const Quantity&); static Quantity abs(const Quantity&); static Quantity integer(const Quantity&); static Quantity frac(const Quantity&); static Quantity floor(const Quantity&); static Quantity ceil(const Quantity&); static Quantity gcd(const Quantity&, const Quantity&); static Quantity idiv(const Quantity&, const Quantity&); static Quantity round(const Quantity&, int prec = 0); static Quantity trunc(const Quantity&, int prec = 0); static Quantity sqrt(const Quantity&); static Quantity cbrt(const Quantity&); static Quantity raise(const Quantity&, int); static Quantity raise(const Quantity&, const Quantity&); static Quantity sgn(const Quantity&); // EXPONENTIAL FUNCTION AND RELATED static Quantity exp(const Quantity&); static Quantity ln(const Quantity&); static Quantity lg(const Quantity&); static Quantity lb(const Quantity&); static Quantity log(const Quantity& base, const Quantity&); static Quantity sinh(const Quantity&); static Quantity cosh(const Quantity&); static Quantity tanh(const Quantity&); static Quantity arsinh(const Quantity&); static Quantity arcosh(const Quantity&); static Quantity artanh(const Quantity&); // COMPLEX static Quantity real(const Quantity&); static Quantity imag(const Quantity&); static Quantity phase(const Quantity&); // TRIGONOMETRY static Quantity sin(const Quantity&); static Quantity cos(const Quantity&); static Quantity tan(const Quantity&); static Quantity cot(const Quantity&); static Quantity sec(const Quantity&); static Quantity csc(const Quantity&); static Quantity arcsin(const Quantity&); static Quantity arccos(const Quantity&); static Quantity arctan(const Quantity&); static Quantity arctan2(const Quantity&, const Quantity & y); // HIGHER MATH FUNCTIONS static Quantity factorial(const Quantity& x, const Quantity& base = CNumber(1)); static Quantity gamma(const Quantity&); static Quantity lnGamma(const Quantity&); static Quantity erf(const Quantity&); static Quantity erfc(const Quantity&); // PROBABILITY static Quantity nCr(const Quantity& n, const Quantity& k); static Quantity nPr(const Quantity& n, const Quantity& r); static Quantity binomialPmf(const Quantity& k, const Quantity& n, const Quantity& p); static Quantity binomialCdf(const Quantity& k, const Quantity& n, const Quantity& p); static Quantity binomialMean(const Quantity& n, const Quantity& p); static Quantity binomialVariance(const Quantity& n, const Quantity& p); static Quantity hypergeometricPmf(const Quantity& k, const Quantity& N, const Quantity& M, const Quantity& n); static Quantity hypergeometricCdf(const Quantity& k, const Quantity& N, const Quantity& M, const Quantity& n); static Quantity hypergeometricMean(const Quantity& N, const Quantity& M, const Quantity& n); static Quantity hypergeometricVariance(const Quantity& N, const Quantity& M, const Quantity& n); static Quantity poissonPmf(const Quantity& k, const Quantity& l); static Quantity poissonCdf(const Quantity& k, const Quantity& l); static Quantity poissonMean(const Quantity& l); static Quantity poissonVariance(const Quantity& l); // LOGIC static Quantity mask (const Quantity&, const Quantity& bits); static Quantity sgnext (const Quantity&, const Quantity& bits); static Quantity ashr(const Quantity&, const Quantity& bits); // IEEE-754 CONVERSION static Quantity decodeIeee754(const Quantity&, const Quantity& exp_bits, const Quantity& significand_bits); static Quantity decodeIeee754(const Quantity&, const Quantity& exp_bits, const Quantity& significand_bits, const Quantity& exp_bias); static Quantity encodeIeee754(const Quantity&, const Quantity& exp_bits, const Quantity& significand_bits); static Quantity encodeIeee754(const Quantity&, const Quantity& exp_bits, const Quantity& significand_bits, const Quantity& exp_bias); }; #endif // QUANTITY_H deepin-calculator-1.0.2/math/rational.cpp000066400000000000000000000137631325241207700203700ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "rational.h" #include "math/hmath.h" #include "../core/numberformatter.h" #include #include #include #include void Rational::normalize() { if(m_denom==0) { m_valid = false; return; } if(m_num==0) { m_denom=1; return; } int g = gcd(abs(m_num), abs(m_denom)); m_num /= g; m_denom /= g; if(m_denom<0) { m_num = -m_num; m_denom = -m_denom; } } int Rational::compare(const Rational &other) const { return m_num*other.m_denom - m_denom*other.m_num; } /* * Find a rational approximation to num using a continued fraction scheme. * Code adapted from the 'Fraction' module for the PYTHON programming language, * authored by Sjoerd Mullender and Jeffrey Yasskin. */ Rational::Rational(const HNumber &num) : m_num(1), m_denom(1), m_valid(1) { if(num.isZero()) { m_num = 0; return; } if(HMath::abs(num)>HNumber(INT_MAX) || HMath::abs(num)MAXD) break; unsigned long long temp1=p0, temp2=p1, temp3=q1; p0 = temp2; q0 = temp3; p1 = temp1 + a*temp2; q1 = q2; if(HMath::frac(val).isZero()) break; val = HNumber(1)/HMath::frac(val); if(val>HNumber(MAXD)) break; } Rational bound(p1, q1); if(num<0) { bound.m_num *= -1; } *this = bound; } Rational::Rational(const double &num): m_num(1), m_denom(1), m_valid(1) { if (num==0) { m_num = 0; return; } if (std::abs(num)>INT_MAX || std::abs(1./num)>INT_MAX) { m_valid = false; return; } const long long MAXD = INT_MAX/2; // maximal denominator long long p0=0, q0=1, p1=1, q1=0; double val = fabs(num); while(true) { unsigned long long a = static_cast(floor(val)); unsigned long long q2 = q0 + a*q1; if(q2>MAXD) break; unsigned long long temp1=p0, temp2=p1, temp3=q1; p0 = temp2; q0 = temp3; p1 = temp1 + a*temp2; q1 = q2; if(val==a) break; val = 1/(val-a); } Rational bound(p1, q1); if(num<0) bound.m_num *= -1; *this = bound; } Rational::Rational(const QString &str) : m_num(0), m_denom(1), m_valid(true) { if(str=="") { m_valid=false; return; } QStringList l = str.split("/"); if(l.size()==1) { bool ok; m_num = l.at(0).toInt(&ok); if(!ok) { m_valid=false; return; } } else if(l.size()==2) { bool ok; m_num = l.at(0).toInt(&ok); if(!ok) { m_valid=false; return; } m_denom = l.at(1).toInt(&ok); if(!ok) { m_valid=false; return; } } } Rational Rational::operator*(const Rational &other) const { return Rational(this->m_num * other.m_num, this->m_denom * other.m_denom); } Rational Rational::operator/(const Rational &other) const { if(other.isZero()) return Rational(1,0); // Rational(1,0) will set m_valid=false return Rational(this->m_num / other.m_num, this->m_denom / other.m_denom); } Rational Rational::operator+(const Rational &other) const { return Rational(this->m_num*other.m_denom + this->m_denom*other.m_num, this->m_denom*other.m_denom); } Rational Rational::operator-(const Rational &other) const { return Rational(this->m_num*other.m_denom - this->m_denom*other.m_num, this->m_denom*other.m_denom); } Rational &Rational::operator=(const Rational &other) { m_num = other.m_num; m_denom = other.m_denom; m_valid = other.m_valid; return *this; } Rational &Rational::operator+=(const Rational &other) { return operator=(*this + other); } Rational &Rational::operator-=(const Rational &other) { return operator=(*this - other); } Rational &Rational::operator*=(const Rational &other) { return operator=(*this * other); } Rational &Rational::operator/=(const Rational &other) { return operator=(*this / other); } bool Rational::operator<(const Rational &other) const { return compare(other)<0; } bool Rational::operator==(const Rational &other) const { return compare(other) == 0; } bool Rational::operator>(const Rational &other) const { return compare(other)>0; } bool Rational::isZero() const { return m_num==0; } bool Rational::isValid() const { return m_valid; } QString Rational::toString() const { if(m_denom==1) return QString::fromLatin1("%1").arg(m_num); return QString::fromLatin1("%1/%2").arg(m_num).arg(m_denom); } HNumber Rational::toHNumber() const { HNumber num(m_num); HNumber denom(m_denom); return num/denom; } double Rational::toDouble() const { return double(m_num)/m_denom; } deepin-calculator-1.0.2/math/rational.h000066400000000000000000000044501325241207700200260ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef RATIONAL_H #define RATIONAL_H class HNumber; class QString; class Rational { int m_num; int m_denom; bool m_valid; inline int gcd(int a, int b) const {return (b==0) ? a : gcd(b, a%b);} void normalize(); int compare(const Rational & other) const; public: Rational() : m_num(0), m_denom(1), m_valid(true) {} Rational(const HNumber &num); Rational(const double &num); Rational(const QString & str); Rational(const int a, const int b) : m_num(a), m_denom(b), m_valid(true) {normalize();} int numerator() const {return m_num;} int denominator() const {return m_denom;} Rational operator*(const Rational & other) const; Rational operator/(const Rational & other) const; Rational operator+(const Rational & other) const; Rational operator-(const Rational & other) const; Rational &operator=(const Rational & other); Rational &operator+=(const Rational & other); Rational &operator-=(const Rational & other); Rational &operator*=(const Rational & other); Rational &operator/=(const Rational & other); bool operator<(const Rational & other) const; bool operator==(const Rational & other) const; bool operator!=(const Rational & other) const {return !operator==(other);} bool operator>(const Rational & other) const; bool isZero() const; bool isValid() const; QString toString() const; HNumber toHNumber( )const; double toDouble() const; }; #endif // RATIONAL_H deepin-calculator-1.0.2/math/units.cpp000066400000000000000000000444461325241207700177230ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "units.h" #include "quantity.h" #include "rational.h" #include #include #define UNIT_CACHE(name, value) \ const Quantity Units::name() \ { \ if (!m_cache.contains(#name)) \ m_cache[#name] = value; \ return (m_cache[#name]); \ } #define BASE_UNIT_CACHE(name, dimension) \ const Quantity Units::name() \ { \ if (!m_cache.contains(#name)) { \ Quantity name(1); \ name.modifyDimension(dimension, 1); \ m_cache[#name] = name; \ } \ return m_cache[#name]; \ } QHash, Unit> Units::m_matchLookup; QMap Units::m_cache; void Units::pushUnit(Quantity q, QString name) { q.cleanDimension(); Unit u(name, q); m_matchLookup.insert(q.getDimension(), u); } unsigned int qHash(QMap dimension) { QStringList keyList(dimension.keys()); QString blob(""); keyList.sort(); for (int i = 0; i < keyList.size(); ++i) { keyList[i].append(dimension[keyList[i]].toString()); blob.append(keyList[i]); } return qHash(blob); } /* * initialize the lookup table for automatic matching */ void Units::initTable() { m_matchLookup.clear(); pushUnit(joule(), "newton meter"); // energy or torque pushUnit(newton(), "newton"); // force pushUnit(watt(), "watt"); // power pushUnit(pascal(), "pascal"); // pressure or energy density pushUnit(coulomb(), "coulomb"); // charge pushUnit(volt(), "volt"); // electrical potential pushUnit(ohm(), "ohm"); // el. resistance pushUnit(siemens(), "siemens"); // el. conductance pushUnit(ohm()*meter(), "ohm meter"); // el. resistivity pushUnit(siemens()/meter(), "siemens/meter"); // el. conductivity pushUnit(siemens()/meter()/mole(), "siemens/(meter mole)"); // molar conductivity pushUnit(farad(), "farad"); // capacitance pushUnit(tesla(), "tesla"); // magnetic flux density pushUnit(weber(), "weber"); // magnetic flux pushUnit(henry(), "henry"); // inductance pushUnit(coulomb()/cbmeter(), "coulomb/meter³"); // electric charge density pushUnit(coulomb()/sqmeter(), "coulomb/meter²"); // surface charge density or el. flux pushUnit(coulomb()/kilogram(), "coulomb/kilogram"); // exposure pushUnit(farad()/meter(), "farad/meter"); // permittivity pushUnit(henry()/meter(), "henry/meter"); // permeability pushUnit(joule()/kilogram()/kelvin(),"joule/(kilogram kelvin)"); // specific heat capacity pushUnit(joule()/mole()/kelvin(), "joule/(mole kelvin"); // molar heat capacity pushUnit(mole()/second()/cbmeter(), "mole/(second meter³)"); // catalytic activity pushUnit(newton()/meter(), "newton/meter"); // surface tension pushUnit(pascal()*second(), "pascal second"); // dynamic viscosity pushUnit(volt()/meter(), "volt/meter"); // el. field pushUnit(watt()/meter()/kelvin(), "watt/(meter kelvin)"); // thermal conductivity pushUnit(watt()/sqmeter(), "watt/meter²"); // heat flux pushUnit(joule()/kelvin(), "joule/kelvin"); // entropy or heat capacity pushUnit(joule()/kilogram(), "joule/kilogram"); // specific energy } void Units::findUnit(Quantity& q) { QString unit_name = ""; CNumber unit(1); q.cleanDimension(); if (m_matchLookup.isEmpty()) initTable(); // Match derived units. if (m_matchLookup.contains(q.getDimension())) { Unit temp(m_matchLookup[q.getDimension()]); q.setDisplayUnit(temp.value.numericValue(), temp.name); } else { // Autogenerate unit name (product of base units). auto dimension = q.getDimension(); auto i = dimension.constBegin(); while (i != dimension.constEnd()) { auto exponent = i.value().toString(); if (exponent.contains('/')) exponent = "^(" + exponent+')'; else if (exponent == "1") exponent = ""; else exponent = '^' + exponent; if (exponent == QLatin1String("^0")) exponent = QString::fromUtf8("⁰"); else if (exponent == QLatin1String("^2")) exponent = QString::fromUtf8("²"); else if (exponent == QLatin1String("^3")) exponent = QString::fromUtf8("³"); else if (exponent == QLatin1String("^4")) exponent = QString::fromUtf8("⁴") ; else if (exponent == QLatin1String("^5")) exponent = QString::fromUtf8("⁵") ; else if (exponent == QLatin1String("^6")) exponent = QString::fromUtf8("⁶") ; else if (exponent == QLatin1String("^7")) exponent = QString::fromUtf8("⁷") ; else if (exponent == QLatin1String("^8")) exponent = QString::fromUtf8("⁸") ; else if (exponent == QLatin1String("^9")) exponent = QString::fromUtf8("⁹") ; else if (exponent == QLatin1String("^-1")) exponent = QString::fromUtf8("⁻¹"); else if (exponent == QLatin1String("^-2")) exponent = QString::fromUtf8("⁻²"); else if (exponent == QLatin1String("^-3")) exponent = QString::fromUtf8("⁻³"); else if (exponent == QLatin1String("^-4")) exponent = QString::fromUtf8("⁻⁴") ; else if (exponent == QLatin1String("^-5")) exponent = QString::fromUtf8("⁻⁵") ; else if (exponent == QLatin1String("^-6")) exponent = QString::fromUtf8("⁻⁶") ; else if (exponent == QLatin1String("^-7")) exponent = QString::fromUtf8("⁻⁷") ; else if (exponent == QLatin1String("^-8")) exponent = QString::fromUtf8("⁻⁸") ; else if (exponent == QLatin1String("^-9")) exponent = QString::fromUtf8("⁻⁹") ; // TODO: Replace this with a lookup to a repository. if (i.key() == "length") unit_name += " meter"; else if (i.key() == "time") unit_name += " second"; else if (i.key() == "mass") unit_name += " kilogram"; else if (i.key() == "el. current") unit_name += " ampere"; else if (i.key() == "amount") unit_name += " mole"; else if (i.key() == "luminous intensity") unit_name += " candela"; else if (i.key() == "temperature") unit_name += " kelvin"; else if (i.key() == "information") unit_name += " bit"; else unit_name += " " + i.key(); // fall back to the dimension name unit_name += exponent; ++i; } q.setDisplayUnit(unit, unit_name.trimmed()); } } #define ADD_UNIT(name) result.append(Unit(#name, name())) #define ADD_UNIT_ALIAS(name, alias) result.append(Unit(#alias, name())) // This list contains the units that wil be set as builtin variables by the evaluator. const QList Units::getList() { QList result; ADD_UNIT(meter); ADD_UNIT(second); ADD_UNIT(kilogram); ADD_UNIT(ampere); ADD_UNIT(mole); ADD_UNIT(candela); ADD_UNIT(kelvin); ADD_UNIT(bit); ADD_UNIT(yocto); ADD_UNIT(zepto); ADD_UNIT(atto); ADD_UNIT(femto); ADD_UNIT(pico); ADD_UNIT(nano); ADD_UNIT(micro); ADD_UNIT(milli); ADD_UNIT(centi); ADD_UNIT(deci); ADD_UNIT(deca); ADD_UNIT(hecto); ADD_UNIT(kilo); ADD_UNIT(mega); ADD_UNIT(giga); ADD_UNIT(tera); ADD_UNIT(peta); ADD_UNIT(exa); ADD_UNIT(zetta); ADD_UNIT(yotta); ADD_UNIT(kibi); ADD_UNIT(mebi); ADD_UNIT(gibi); ADD_UNIT(tebi); ADD_UNIT(pebi); ADD_UNIT(exbi); ADD_UNIT(zebi); ADD_UNIT(yobi); ADD_UNIT(sqmeter); ADD_UNIT(cbmeter); ADD_UNIT(newton); ADD_UNIT(hertz); ADD_UNIT(joule); ADD_UNIT(watt); ADD_UNIT(pascal); ADD_UNIT(coulomb); ADD_UNIT(volt); ADD_UNIT(ohm); ADD_UNIT(farad); ADD_UNIT(tesla); ADD_UNIT(weber); ADD_UNIT(henry); ADD_UNIT(siemens); ADD_UNIT(becquerel); ADD_UNIT(gray); ADD_UNIT(sievert); ADD_UNIT(katal); ADD_UNIT(steradian); ADD_UNIT(lumen); ADD_UNIT(lux); ADD_UNIT(metric_ton); ADD_UNIT(short_ton); ADD_UNIT(long_ton); ADD_UNIT(pound); ADD_UNIT(ounce); ADD_UNIT(grain); ADD_UNIT(gram); ADD_UNIT(atomic_mass_unit); ADD_UNIT(carat); ADD_UNIT(micron); ADD_UNIT(angstrom); ADD_UNIT(astronomical_unit); ADD_UNIT(lightyear); ADD_UNIT(lightsecond); ADD_UNIT(lightminute); ADD_UNIT(parsec); ADD_UNIT(inch); ADD_UNIT(foot); ADD_UNIT(yard); ADD_UNIT(mile); ADD_UNIT(rod); ADD_UNIT(furlong); ADD_UNIT(fathom); ADD_UNIT(nautical_mile); ADD_UNIT(cable); ADD_UNIT(UK_gallon); ADD_UNIT(US_gallon); ADD_UNIT_ALIAS(US_gallon, gallon_US); ADD_UNIT_ALIAS(UK_gallon, gallon_UK); ADD_UNIT_ALIAS(UK_gallon, imperial_gallon); ADD_UNIT(UK_quart); ADD_UNIT(US_quart); ADD_UNIT_ALIAS(US_quart, quart_US); ADD_UNIT_ALIAS(UK_quart, quart_UK); ADD_UNIT(UK_pint); ADD_UNIT(US_pint); ADD_UNIT_ALIAS(US_pint, pint_US); ADD_UNIT_ALIAS(UK_pint, pint_UK); ADD_UNIT(UK_fluid_ounce); ADD_UNIT(US_fluid_ounce); ADD_UNIT_ALIAS(US_fluid_ounce, fluid_ounce_US); ADD_UNIT_ALIAS(UK_fluid_ounce, fluid_ounce_UK); ADD_UNIT(liter); ADD_UNIT(minute); ADD_UNIT(hour); ADD_UNIT(day); ADD_UNIT(week); ADD_UNIT(julian_year); ADD_UNIT(tropical_year); ADD_UNIT(sidereal_year); ADD_UNIT_ALIAS(julian_year, year_julian); ADD_UNIT_ALIAS(tropical_year, year_tropical); ADD_UNIT_ALIAS(sidereal_year, year_sidereal); ADD_UNIT(percent); ADD_UNIT(ppm); ADD_UNIT(ppb); ADD_UNIT(karat); ADD_UNIT(bar); ADD_UNIT(atmosphere); ADD_UNIT(torr); ADD_UNIT(pounds_per_sqinch); ADD_UNIT(electron_volt); ADD_UNIT(calorie); ADD_UNIT(british_thermal_unit); ADD_UNIT(nat); ADD_UNIT(hartley); ADD_UNIT(byte); ADD_UNIT(tablespoon); ADD_UNIT(teaspoon); ADD_UNIT(cup); ADD_UNIT(gravity); ADD_UNIT_ALIAS(gravity, force); ADD_UNIT(speed_of_light); ADD_UNIT(speed_of_sound_STP); ADD_UNIT(elementary_charge); ADD_UNIT(knot); ADD_UNIT(horsepower); return result; } BASE_UNIT_CACHE(meter, "length") BASE_UNIT_CACHE(second, "time") BASE_UNIT_CACHE(kilogram, "mass") BASE_UNIT_CACHE(ampere, "el. current") BASE_UNIT_CACHE(mole, "amount") BASE_UNIT_CACHE(kelvin, "temperature") BASE_UNIT_CACHE(candela, "luminous intensity") BASE_UNIT_CACHE(bit, "information") UNIT_CACHE(yocto, HNumber("1e-24")) UNIT_CACHE(zepto, HNumber("1e-21")) UNIT_CACHE(atto, HNumber("1e-18")) UNIT_CACHE(femto, HNumber("1e-15")) UNIT_CACHE(pico, HNumber("1e-12")) UNIT_CACHE(nano, HNumber("1e-9")) UNIT_CACHE(micro, HNumber("1e-6")) UNIT_CACHE(milli, HNumber("1e-3")) UNIT_CACHE(centi, HNumber("1e-2")) UNIT_CACHE(deci, HNumber("1e-1")) UNIT_CACHE(deca, HNumber("1e1")) UNIT_CACHE(hecto, HNumber("1e2")) UNIT_CACHE(kilo, HNumber("1e3")) UNIT_CACHE(mega, HNumber("1e6")) UNIT_CACHE(giga, HNumber("1e9")) UNIT_CACHE(tera, HNumber("1e12")) UNIT_CACHE(peta, HNumber("1e15")) UNIT_CACHE(exa, HNumber("1e18")) UNIT_CACHE(zetta, HNumber("1e21")) UNIT_CACHE(yotta, HNumber("1e24")) UNIT_CACHE(kibi, HNumber("1024")) UNIT_CACHE(mebi, kibi()*kibi()) UNIT_CACHE(gibi, kibi()*mebi()) UNIT_CACHE(tebi, kibi()*gibi()) UNIT_CACHE(pebi, kibi()*tebi()) UNIT_CACHE(exbi, kibi()*pebi()) UNIT_CACHE(zebi, kibi()*exbi()) UNIT_CACHE(yobi, kibi()*zebi()) UNIT_CACHE(newton, meter() * kilogram() / (second()*second())) UNIT_CACHE(hertz, Quantity(1) / second()) UNIT_CACHE(pascal, newton() / sqmeter()) UNIT_CACHE(joule, newton() * meter()) UNIT_CACHE(watt, joule() / second()) UNIT_CACHE(coulomb, ampere() * second()) UNIT_CACHE(volt, watt() / ampere()) UNIT_CACHE(farad, coulomb() / volt()) UNIT_CACHE(ohm, volt() / ampere()) UNIT_CACHE(siemens, ampere() / volt()) UNIT_CACHE(weber, volt() * second()) UNIT_CACHE(tesla, weber() / sqmeter()) UNIT_CACHE(henry, weber() / ampere()) UNIT_CACHE(becquerel, Quantity(1) / second()) UNIT_CACHE(gray, joule() / kilogram()) UNIT_CACHE(sievert, joule() / kilogram()) UNIT_CACHE(katal, mole() / second()) UNIT_CACHE(steradian, 1) UNIT_CACHE(lumen, candela()*steradian()) UNIT_CACHE(lux, lumen()/sqmeter()) UNIT_CACHE(sqmeter, meter() * meter()) UNIT_CACHE(cbmeter, sqmeter() * meter()) UNIT_CACHE(metric_ton, mega()*gram()) UNIT_CACHE(gram, milli()*kilogram()) UNIT_CACHE(pound, HNumber("0.45359237") * kilogram()) UNIT_CACHE(ounce, pound() / HNumber(16)) UNIT_CACHE(grain, pound() / HNumber(7000)) UNIT_CACHE(short_ton, HNumber(2000) * pound()) UNIT_CACHE(long_ton, HNumber(2240) * pound()) UNIT_CACHE(atomic_mass_unit, HNumber("1.660539040e-27") * kilogram()) // http://physics.nist.gov/cgi-bin/cuu/Value?tukg UNIT_CACHE(carat, HNumber(200) * milli()*gram()) // Do not confuse with karat below. UNIT_CACHE(micron, micro()*meter()) UNIT_CACHE(angstrom, HNumber("1e-10") * meter()) UNIT_CACHE(astronomical_unit, HNumber("149597870700") * meter()) // IAU 2012 Resolution B2. UNIT_CACHE(lightyear, speed_of_light() * julian_year()) UNIT_CACHE(lightminute, speed_of_light() * minute()) UNIT_CACHE(lightsecond, speed_of_light() * second()) UNIT_CACHE(parsec, HNumber(648000)/HMath::pi() * astronomical_unit()) // IAU 2015 Resolution B2. UNIT_CACHE(inch, HNumber("0.0254") * meter()) // International inch. UNIT_CACHE(foot, HNumber(12) * inch()) UNIT_CACHE(yard, HNumber(36) * inch()) UNIT_CACHE(mile, HNumber(1760) * yard()) UNIT_CACHE(rod, HNumber("5.5") * yard()) UNIT_CACHE(furlong, HNumber(40) * rod()) UNIT_CACHE(fathom, HNumber(6) * foot()) UNIT_CACHE(nautical_mile, HNumber("1852") * meter()) UNIT_CACHE(cable, HNumber("0.1") * nautical_mile()) UNIT_CACHE(are, HNumber(100) * sqmeter()) UNIT_CACHE(hectare, HNumber(100) * are()) UNIT_CACHE(acre, mile()*mile() / HNumber(640)) UNIT_CACHE(US_gallon, HNumber("3.785") * liter()) UNIT_CACHE(UK_gallon, HNumber("4.54609") * liter()) UNIT_CACHE(US_quart, US_gallon() / HNumber(4)) UNIT_CACHE(UK_quart, UK_gallon() / HNumber(4)) UNIT_CACHE(US_pint, US_gallon() / HNumber(8)) UNIT_CACHE(UK_pint, UK_gallon() / HNumber(8)) UNIT_CACHE(US_fluid_ounce, US_gallon() / HNumber(128)) UNIT_CACHE(UK_fluid_ounce, UK_gallon() / HNumber(160)) UNIT_CACHE(liter, milli() * cbmeter()) UNIT_CACHE(minute, HNumber(60) * second()) UNIT_CACHE(hour, HNumber(60) * minute()) UNIT_CACHE(day, HNumber(24) * hour()) UNIT_CACHE(week, HNumber(7) * day()) UNIT_CACHE(julian_year, HNumber("365.25") * day()) UNIT_CACHE(tropical_year, HNumber("365.24219") * day()) // Approx.: changes over time due to Earth's precession. UNIT_CACHE(sidereal_year, HNumber("365.25636") * day()) // http://hpiers.obspm.fr/eop-pc/models/constants.html UNIT_CACHE(percent, HNumber("0.01")) UNIT_CACHE(ppm, HNumber("1e-6")) UNIT_CACHE(ppb, HNumber("1e-9")) UNIT_CACHE(karat, Rational(1,24).toHNumber()) // Do not confuse with carat above. UNIT_CACHE(bar, HNumber("1e5") * pascal()) UNIT_CACHE(atmosphere, HNumber("1.01325") * bar()) UNIT_CACHE(torr, atmosphere() / HNumber(760)) UNIT_CACHE(pounds_per_sqinch, pound() * gravity() / (inch()*inch())) UNIT_CACHE(electron_volt, elementary_charge() * volt()) UNIT_CACHE(calorie, HNumber("4.1868") * joule()) // International Table calorie. UNIT_CACHE(british_thermal_unit, HNumber("1055.056") * joule()) // International standard ISO 31-4. UNIT_CACHE(nat, bit() / HMath::ln(2)) UNIT_CACHE(hartley, HMath::ln(10) * nat()) UNIT_CACHE(byte, HNumber(8) * bit()) UNIT_CACHE(tablespoon, HNumber(15) * milli()*liter()) UNIT_CACHE(teaspoon, HNumber(5) * milli()*liter()) UNIT_CACHE(cup, HNumber(240) * milli()*liter()) UNIT_CACHE(gravity, HNumber("9.80665") * newton() / kilogram()) // 3rd CGPM (1901, CR 70). UNIT_CACHE(speed_of_light, HNumber(299792458) * meter() / second()) UNIT_CACHE(elementary_charge, HNumber("1.6021766208e-19") * coulomb()) // http://physics.nist.gov/cgi-bin/cuu/Value?e UNIT_CACHE(speed_of_sound_STP, HNumber(331) * meter()/second()) UNIT_CACHE(knot, nautical_mile()/hour()) UNIT_CACHE(horsepower, HNumber(550) * foot() * pound() * gravity() / second()) // Imperial horsepower. deepin-calculator-1.0.2/math/units.h000066400000000000000000000153061325241207700173610ustar00rootroot00000000000000// This file is part of the SpeedCrunch project // Copyright (C) 2015 Pol Welter // Copyright (C) 2016 @heldercorreia // // 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 2 // 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; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef UNITS_H #define UNITS_H #include #include #include "math/quantity.h" class Rational; struct Unit { QString name; Quantity value; Unit(QString name, Quantity value) : name(name) , value(value) { } Unit() : name("") , value(1) { } }; class Units { static void pushUnit(Quantity q, QString name); static QHash, Unit> m_matchLookup; static QMap m_cache; static void initTable(); public: static void findUnit(Quantity& q); static void clearCache() { m_cache.clear(); } static const QList getList(); // Base SI units. static const Quantity meter(); static const Quantity second(); static const Quantity kilogram(); static const Quantity ampere(); static const Quantity mole(); static const Quantity kelvin(); static const Quantity candela(); // Base non-SI units. static const Quantity bit(); // SI prefixes. static const Quantity yocto(); static const Quantity zepto(); static const Quantity atto(); static const Quantity femto(); static const Quantity pico(); static const Quantity nano(); static const Quantity micro(); static const Quantity milli(); static const Quantity centi(); static const Quantity deci(); static const Quantity deca(); static const Quantity hecto(); static const Quantity kilo(); static const Quantity mega(); static const Quantity giga(); static const Quantity tera(); static const Quantity peta(); static const Quantity exa(); static const Quantity zetta(); static const Quantity yotta(); // Binary prefixes. static const Quantity kibi(); static const Quantity mebi(); static const Quantity gibi(); static const Quantity tebi(); static const Quantity pebi(); static const Quantity exbi(); static const Quantity zebi(); static const Quantity yobi(); // Derived SI units. static const Quantity sqmeter(); static const Quantity cbmeter(); static const Quantity newton(); static const Quantity hertz(); static const Quantity steradian(); static const Quantity pascal(); static const Quantity joule(); static const Quantity watt(); static const Quantity coulomb(); static const Quantity volt(); static const Quantity farad(); static const Quantity ohm(); static const Quantity siemens(); static const Quantity weber(); static const Quantity tesla(); static const Quantity henry(); static const Quantity lumen(); static const Quantity lux(); static const Quantity becquerel(); static const Quantity gray(); static const Quantity sievert(); static const Quantity katal(); // Derived from SI units. // Mass. static const Quantity metric_ton(); static const Quantity short_ton(); static const Quantity long_ton(); static const Quantity pound(); static const Quantity ounce(); static const Quantity grain(); static const Quantity gram(); static const Quantity atomic_mass_unit(); static const Quantity carat(); // Distance/length. static const Quantity micron(); static const Quantity angstrom(); static const Quantity astronomical_unit(); static const Quantity lightyear(); static const Quantity lightsecond(); static const Quantity lightminute(); static const Quantity parsec(); // US measures. static const Quantity inch(); static const Quantity foot(); static const Quantity yard(); static const Quantity mile(); static const Quantity rod(); static const Quantity furlong(); // Nautical (US). static const Quantity fathom(); static const Quantity nautical_mile(); static const Quantity cable(); // Area. static const Quantity are(); static const Quantity hectare(); static const Quantity acre(); // Volume. static const Quantity US_gallon(); static const Quantity UK_gallon(); static const Quantity US_quart(); static const Quantity UK_quart(); static const Quantity US_pint(); static const Quantity UK_pint(); static const Quantity US_fluid_ounce(); static const Quantity UK_fluid_ounce(); static const Quantity liter(); // Time. static const Quantity minute(); static const Quantity hour(); static const Quantity day(); static const Quantity week(); static const Quantity julian_year(); static const Quantity tropical_year(); static const Quantity sidereal_year(); // Concentration. static const Quantity percent(); static const Quantity ppm(); static const Quantity ppb(); static const Quantity karat(); // Pressure. static const Quantity bar(); static const Quantity atmosphere(); static const Quantity torr(); static const Quantity pounds_per_sqinch(); // Energy. static const Quantity electron_volt(); static const Quantity calorie(); static const Quantity british_thermal_unit(); // Information. static const Quantity nat(); static const Quantity hartley(); static const Quantity byte(); // Cooking. // Note: these again differ from US to UK, Australia, Japan, ... // Since for cooking generally not that high a precision is // required, let's just stick with the so called 'legal' variant. static const Quantity tablespoon(); static const Quantity teaspoon(); static const Quantity cup(); // Various others. // TODO: Some of these are constants that should be moved once constants are also accessible via builtin names. static const Quantity gravity(); static const Quantity speed_of_light(); static const Quantity elementary_charge(); static const Quantity speed_of_sound_STP(); static const Quantity knot(); static const Quantity horsepower(); }; #endif // UNITS_H deepin-calculator-1.0.2/qss/000077500000000000000000000000001325241207700157165ustar00rootroot00000000000000deepin-calculator-1.0.2/qss/dark.qss000066400000000000000000000025601325241207700173720ustar00rootroot00000000000000QLineEdit { background-color: transparent; color: #B4B4B4; border: none; } #TextButton { font-size: 18px; font-weight: 300; color: #E0E0E0; background-color: #202020; border: none; margin: 0px; } #TextButton:hover { color: #FFFFFF; font-size: 20px; font-weight: 400; border: 1px solid #2D2D2D; background-color: #2D2D2D; } #TextButton:pressed { font-size: 18px; color: #606060; background-color: #101010; border: none; } #SymbolButton { font-weight: 400; font-size: 22px; color: #2CA7F8; background-color: #202020; border: none; } #SymbolButton:hover { font-weight: 500; font-size: 24px; border: 1px solid #2D2D2D; background-color: #2D2D2D; } #SymbolButton:pressed { font-weight: 400; font-size: 22px; background-color: #101010; border: none; } #EqualButton { font-weight: 400; font-size: 22px; color: #FFFFFF; border: none; background-color: #2CA7F8; } #EqualButton:hover { font-weight: 500; font-size: 24px; background-color: qlineargradient(x1:0 y1:0, x2:0 y2:1, stop:0 #31c9ff, stop:1 #00abff); border: 1px solid #2CA7F8; } #EqualButton:pressed { font-weight: 400; font-size: 22px; color: #A8CFF8; border: none; background-color: qlineargradient(x1:0 y1:0, x2:0 y2:1, stop:0 #2472e8, stop:1 #2ca7fb); } deepin-calculator-1.0.2/qss/light.qss000066400000000000000000000026121325241207700175560ustar00rootroot00000000000000QLineEdit { background-color: transparent; color: #303030; border: none; } #TextButton { font-size: 18px; font-weight: 300; color: #545454; background-color: #FFFFFF; border: none; margin: 0px; } #TextButton:hover { color: #000000; font-size: 20px; font-weight: 400; border: 1px solid #A7E0FF; background-color: #FFFFFF; } #TextButton:pressed { font-size: 18px; color: #606060; background-color: #EFEFEF; border: 1px solid #CBCBCB; } #SymbolButton { font-weight: 400; font-size: 22px; color: #2CA7F8; background-color: #FFFFFF; border: none; } #SymbolButton:hover { font-weight: 500; font-size: 24px; border: 1px solid #A7E0FF; background-color: #FFFFFF; } #SymbolButton:pressed { font-weight: 400; font-size: 22px; background-color: #EFEFEF; border: 1px solid #CBCBCB; } #EqualButton { font-weight: 400; font-size: 22px; color: #FFFFFF; border: none; background-color: #2CA7F8; } #EqualButton:hover { font-weight: 500; font-size: 24px; background-color: qlineargradient(x1:0 y1:0, x2:0 y2:1, stop:0 #31c9ff, stop:1 #00abff); border: 1px solid #2CA7F8; } #EqualButton:pressed { font-weight: 400; font-size: 22px; color: #A8CFF8; border: none; background-color: qlineargradient(x1:0 y1:0, x2:0 y2:1, stop:0 #2472e8, stop:1 #2ca7fb); } deepin-calculator-1.0.2/src/000077500000000000000000000000001325241207700156775ustar00rootroot00000000000000deepin-calculator-1.0.2/src/backbutton.cpp000066400000000000000000000020251325241207700205360ustar00rootroot00000000000000#include "backbutton.h" #include "dthememanager.h" #include DWIDGET_USE_NAMESPACE BackButton::BackButton(QWidget *parent) : TextButton(nullptr, parent), m_iconWidget(new QSvgWidget) { setLayout(new QHBoxLayout(this)); layout()->addWidget(m_iconWidget); init(); connect(DThemeManager::instance(), &DThemeManager::themeChanged, this, &BackButton::init); } BackButton::~BackButton() { } void BackButton::mousePressEvent(QMouseEvent *e) { init(); TextButton::mousePressEvent(e); } void BackButton::mouseReleaseEvent(QMouseEvent *e) { m_iconWidget->setFixedSize(26, 26); TextButton::mouseReleaseEvent(e); } void BackButton::enterEvent(QEvent *e) { m_iconWidget->setFixedSize(26, 26); TextButton::enterEvent(e); } void BackButton::leaveEvent(QEvent *e) { init(); TextButton::leaveEvent(e); } void BackButton::init() { m_iconWidget->load(QString(":/images/delete_%1_normal.svg").arg(DThemeManager::instance()->theme())); m_iconWidget->setFixedSize(23, 23); } deepin-calculator-1.0.2/src/backbutton.h000066400000000000000000000007011325241207700202020ustar00rootroot00000000000000#ifndef BACKBUTTON_H #define BACKBUTTON_H #include "textbutton.h" #include class BackButton : public TextButton { Q_OBJECT public: BackButton(QWidget *parent = nullptr); ~BackButton(); protected: void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void enterEvent(QEvent *); void leaveEvent(QEvent *); private: void init(); private: QSvgWidget *m_iconWidget; }; #endif deepin-calculator-1.0.2/src/dsettings.cpp000066400000000000000000000014511325241207700204100ustar00rootroot00000000000000#include "dsettings.h" #include #include #include DSettings::DSettings(QObject *parent) : QObject(parent) { m_settings = new QSettings(QDir(configPath()).filePath("config.conf"), QSettings::IniFormat); if (m_settings->value("theme").toString().isEmpty()) { setOption("theme", "light"); } } DSettings::~DSettings() { delete m_settings; } QString DSettings::configPath() { return QDir(QDir(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first()).filePath(qApp->organizationName())).filePath(qApp->applicationName()); } QVariant DSettings::getOption(const QString &key) { return m_settings->value(key); } void DSettings::setOption(const QString &key, const QVariant &value) { m_settings->setValue(key, value); } deepin-calculator-1.0.2/src/dsettings.h000066400000000000000000000005501325241207700200540ustar00rootroot00000000000000#ifndef SETTINGS_H #define SETTINGS_H #include class DSettings : public QObject { Q_OBJECT public: DSettings(QObject *parent = nullptr); ~DSettings(); QString configPath(); QVariant getOption(const QString &key); void setOption(const QString &key, const QVariant &value); private: QSettings *m_settings; }; #endif deepin-calculator-1.0.2/src/expressionlist.cpp000066400000000000000000000131321325241207700214760ustar00rootroot00000000000000#include #include #include #include #include #include #include "expressionlist.h" #include "utils.h" ExpressionList::ExpressionList(QWidget *parent) : QWidget(parent) { m_eval = Evaluator::instance(); m_layout = new QVBoxLayout(this); m_listView = new ListView; m_inputEdit = new InputEdit; m_layout->setMargin(0); m_layout->setSpacing(0); m_layout->addWidget(m_listView); m_layout->addWidget(m_inputEdit); m_inputEdit->setTextMargins(10, 0, 10, 8); m_inputEdit->setFixedHeight(55); m_inputEdit->setAlignment(Qt::AlignRight); m_isContinue = true; m_isAllClear = false; setMinimumHeight(160); autoZoomFontSize(); connect(m_inputEdit, &InputEdit::textChanged, this, &ExpressionList::textChanged); connect(m_inputEdit, &InputEdit::inputKeyPressEvent, this, &ExpressionList::inputKeyPressEvent); } ExpressionList::~ExpressionList() { delete m_listView; delete m_inputEdit; } void ExpressionList::update() { m_listView->scrollToBottom(); autoZoomFontSize(); } void ExpressionList::setContinue(const bool &mark) { m_isContinue = mark; } QString ExpressionList::getInputEditText() const { return m_inputEdit->text(); } void ExpressionList::enterNumberEvent(const QString &num, bool isKeyPress) { if (!m_isContinue) { // the cursor position at the end, it will clear edit text. if (cursorPosAtEnd()) { m_inputEdit->clear(); } m_isContinue = true; } if (!isKeyPress) { m_inputEdit->insert(num); } m_isAllClear = false; emit clearStateChanged(false); } void ExpressionList::enterPointEvent() { if (!m_isContinue) { if (cursorPosAtEnd()) { m_inputEdit->clear(); m_inputEdit->insert("0."); } else { m_inputEdit->insert("."); } m_isContinue = true; } else { m_inputEdit->insert("."); } } void ExpressionList::enterSymbolEvent(const QString &str) { m_inputEdit->insert(str); m_isContinue = true; } void ExpressionList::enterBracketsEvent() { const int currentPos = m_inputEdit->cursorPosition(); m_inputEdit->insert("()"); m_inputEdit->setCursorPosition(currentPos + 1); m_isAllClear = false; m_isContinue = true; } void ExpressionList::enterBackspaceEvent() { m_inputEdit->backspace(); m_isContinue = true; m_isAllClear = false; } void ExpressionList::enterClearEvent() { if (m_isAllClear) { m_listView->clearItems(); m_isAllClear = false; emit clearStateChanged(false); } else { m_inputEdit->clear(); m_isAllClear = true; emit clearStateChanged(true); } } void ExpressionList::enterEqualEvent() { if (m_inputEdit->text().isEmpty()) return; QString str = m_eval->autoFix(formatExp(m_inputEdit->expressionText())); m_eval->setExpression(str); auto quantity = m_eval->evalUpdateAns(); if (m_eval->error().isEmpty()) { if (!quantity.isNan() && !m_eval->isUserFunctionAssign()) { Quantity ans = m_eval->evalUpdateAns(); const QString result = DMath::format(ans, Quantity::Format::Fixed()); QString formatResult = Utils::formatThousandsSeparators(result); if (formatResult == m_inputEdit->text()) { return; } m_listView->addItem(m_inputEdit->text() + "=" + formatResult); formatResult.replace("-", "-"); m_inputEdit->setAnswer(formatResult, ans); m_isContinue = false; } } else { m_listView->addItem(m_inputEdit->text() + "=" + tr("Expression Error")); } } void ExpressionList::copyResultToClipboard() { const auto str = m_eval->autoFix(formatExp(m_inputEdit->text())); m_eval->setExpression(str); if (!m_eval->error().isEmpty()) { QApplication::clipboard()->setText(m_inputEdit->text()); } else { const QString result = DMath::format(m_eval->evalUpdateAns(), Quantity::Format::Fixed()); QApplication::clipboard()->setText(result); } } int ExpressionList::getItemsCount() { return m_listView->getItemsCount(); } void ExpressionList::textChanged(const QString &text) { const int oldPos = m_inputEdit->cursorPosition(); const QString exp = QString(text).replace("(", "(").replace(")", ")") .replace(",", "").replace("××", "^"); const QString reformatExp = Utils::reformatSeparators(exp); m_inputEdit->setText(reformatExp); const int newPos = m_inputEdit->cursorPosition(); m_inputEdit->setCursorPosition(oldPos + (newPos - text.count())); // make font size of inputEdit fit text content. autoZoomFontSize(); m_isAllClear = false; m_isContinue = true; emit clearStateChanged(false); } void ExpressionList::autoZoomFontSize() { QFont font; for (int i = 28; i > 8; --i) { font.setPointSize(i); QFontMetrics fm(font); int fontWidth = fm.width(m_inputEdit->text()); int editWidth = m_inputEdit->width() - 30; if (fontWidth < editWidth) { break; } } m_inputEdit->setFont(font); } QString ExpressionList::formatExp(const QString &exp) { return QString(exp).replace("+", "+") .replace("-", "-") .replace("×", "*") .replace("÷", "/") .replace(",", ""); } bool ExpressionList::cursorPosAtEnd() { return m_inputEdit->cursorPosition() == m_inputEdit->text().count(); } deepin-calculator-1.0.2/src/expressionlist.h000066400000000000000000000022141325241207700211420ustar00rootroot00000000000000#ifndef EXPRESSIONLIST_H #define EXPRESSIONLIST_H #include #include #include "listview.h" #include "inputedit.h" #include "core/evaluator.h" class ExpressionList : public QWidget { Q_OBJECT public: ExpressionList(QWidget *parent = nullptr); ~ExpressionList(); void update(); void setContinue(const bool &mark); QString getInputEditText() const; public slots: void enterNumberEvent(const QString &num, bool isKeyPress = false); void enterPointEvent(); void enterSymbolEvent(const QString &str); void enterBracketsEvent(); void enterBackspaceEvent(); void enterClearEvent(); void enterEqualEvent(); void copyResultToClipboard(); int getItemsCount(); private slots: void textChanged(const QString &text); signals: void clearStateChanged(bool isAllClear); void inputKeyPressEvent(QKeyEvent *); private: Evaluator *m_eval; bool m_isContinue; bool m_isAllClear; QVBoxLayout *m_layout; ListView *m_listView; InputEdit *m_inputEdit; void autoZoomFontSize(); QString formatExp(const QString &exp); bool cursorPosAtEnd(); }; #endif deepin-calculator-1.0.2/src/inputedit.cpp000066400000000000000000000147041325241207700204160ustar00rootroot00000000000000#include "inputedit.h" #include "utils.h" #include "math/floatconfig.h" #include #include #define NOT_USED(x) ( (void)(x) ) InputEdit::InputEdit(QLineEdit *parent) : QLineEdit(parent) { m_ans = 0; m_ansStart = 0; m_ansLength = 0; m_ansVaild = false; m_curInAns = false; m_curOnAnsLeft = false; m_oldText = ""; setAttribute(Qt::WA_InputMethodEnabled, false); setAttribute(Qt::WA_TranslucentBackground); connect(this, &QLineEdit::textChanged, this, &InputEdit::handleTextChanged); connect(this, &QLineEdit::cursorPositionChanged, this, &InputEdit::handleCursorPositionChanged); connect(this, &QLineEdit::selectionChanged, [=] { int pos = this->cursorPosition(); this->cursorPositionChanged(pos, pos); }); } InputEdit::~InputEdit() { } void InputEdit::mouseDoubleClickEvent(QMouseEvent *e) { QLineEdit::mouseDoubleClickEvent(e); if (e->button() == Qt::LeftButton) { int position = cursorPositionAt(e->pos()); int posBegin = findWordBeginPosition(position); int posEnd = findWordEndPosition(position); setSelection(posBegin, posEnd - posBegin + 1); } } void InputEdit::keyPressEvent(QKeyEvent *e) { const bool isPressCtrl = e->modifiers() == Qt::ControlModifier; switch (e->key()) { case Qt::Key_0: case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: case Qt::Key_8: case Qt::Key_9: emit inputKeyPressEvent(e); QLineEdit::keyPressEvent(e); break; case Qt::Key_Plus: case Qt::Key_Minus: case Qt::Key_Underscore: case Qt::Key_Asterisk: case Qt::Key_Slash: case Qt::Key_Period: case Qt::Key_Percent: case Qt::Key_Equal: case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: emit inputKeyPressEvent(e); break; case Qt::Key_ParenLeft: case Qt::Key_ParenRight: emit inputKeyPressEvent(e); QLineEdit::keyPressEvent(e); break; case Qt::Key_Backspace: emit inputKeyPressEvent(e); backspace(); break; case Qt::Key_A: if (isPressCtrl) { QLineEdit::keyPressEvent(e); } break; case Qt::Key_C: if (isPressCtrl) { if (!hasSelectedText()) { emit inputKeyPressEvent(e); return; } else { QLineEdit::keyPressEvent(e); } } break; case Qt::Key_V: if (isPressCtrl) { QLineEdit::keyPressEvent(e); } break; case Qt::Key_X: if (isPressCtrl) { QLineEdit::keyPressEvent(e); } else { emit inputKeyPressEvent(e); } break; case Qt::Key_Z: if (isPressCtrl) { QLineEdit::keyPressEvent(e); } break; case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Home: case Qt::Key_End: case Qt::Key_Delete: QLineEdit::keyPressEvent(e); break; } } void InputEdit::handleTextChanged(const QString &text) { if (m_curInAns) { m_ansLength = 0; } else if (m_curOnAnsLeft && m_oldText.length() != 0) { int nl = text.length(); int ol = m_oldText.length(); int l = std::min(nl, ol); int i = 1; for (; i <= l && text[nl - i] == m_oldText[ol - i]; i++) {} int diff = (nl - i) - (ol - i); m_ansStart += diff; } int ans_end = m_ansStart + m_ansLength; m_ansVaild = m_ansLength != 0 && (m_ansStart == 0 || !text[m_ansStart - 1].isDigit()) && (ans_end == text.length() || !text[ans_end].isDigit()); // this->heilightAns(m_ansStart, m_ansVaild ? m_ansLength : 0); m_oldText = text; } void InputEdit::handleCursorPositionChanged(int old_pos, int new_pos) { NOT_USED(old_pos); int ans_end = m_ansStart + m_ansLength; int sel_start = this->selectionStart(); int sel_end = sel_start + this->selectedText().length(); if (new_pos > m_ansStart && new_pos < ans_end) { m_curInAns = true; } else if (this->hasSelectedText() && ((sel_start >= m_ansStart && sel_start < ans_end) || (sel_end > m_ansStart && sel_end <= ans_end) || (sel_start < m_ansStart && sel_end > ans_end))) { m_curInAns = true; } else if (new_pos <= m_ansStart) { m_curInAns = false; m_curOnAnsLeft = true; } else { m_curInAns = false; m_curOnAnsLeft = false; } } bool InputEdit::isSymbolCategoryChanged(int pos1, int pos2) { QString str = text(); QChar::Category category1 = str.at(pos1).category(); QChar::Category category2 = str.at(pos2).category(); if (category1 == QChar::Number_DecimalDigit || category1 == QChar::Punctuation_Other) { if (category2 == QChar::Number_DecimalDigit || category2 == QChar::Punctuation_Other) { return false ; } } return true; } int InputEdit::findWordBeginPosition(int pos) { QString str = text(); if (0 >= pos) { return 0; } while (pos > 0) { pos--; if (isSymbolCategoryChanged(pos, pos + 1)) { return pos + 1; } } return 0; } int InputEdit::findWordEndPosition(int pos) { QString str = text(); if (pos >= str.length()) { return str.length() - 1; } while (pos < str.length() - 1) { pos++; if (isSymbolCategoryChanged(pos, pos - 1)) { return pos - 1; } } return str.length() - 1; } void InputEdit::clear() { m_ansLength = 0; setText(""); } void InputEdit::setAnswer(QString & str, const Quantity & ans) { m_ans = ans; m_ansStart = 0; m_ansLength = str.length(); m_oldText = ""; setText(str); } void InputEdit::heilightAns(int start, int length) { QInputMethodEvent::AttributeType type = QInputMethodEvent::TextFormat; start = start - cursorPosition(); QTextCharFormat f; f.setFontWeight(950); QList attributes; attributes.append(QInputMethodEvent::Attribute(type, start, length, f)); QInputMethodEvent event(QString(), attributes); QCoreApplication::sendEvent(this, &event); } QString InputEdit::expressionText() { QString r = text(); if (m_ansVaild) { QString ans = DMath::format(m_ans, Quantity::Format::Precision(DECPRECISION)); r.remove(m_ansStart, m_ansLength); r.insert(m_ansStart, ans); } return r; } deepin-calculator-1.0.2/src/inputedit.h000066400000000000000000000017341325241207700200620ustar00rootroot00000000000000#ifndef INPUTEDIT_H #define INPUTEDIT_H #include "math/quantity.h" #include class InputEdit : public QLineEdit { Q_OBJECT public: InputEdit(QLineEdit *parent = nullptr); ~InputEdit(); void setAnswer(QString & str, const Quantity & ans); void clear(); QString expressionText(); signals: void inputKeyPressEvent(QKeyEvent *e); protected: void mouseDoubleClickEvent(QMouseEvent *); void keyPressEvent(QKeyEvent *); void handleTextChanged(const QString &text); void handleCursorPositionChanged(int old_pos, int new_pos); private: Quantity m_ans; //Previously calculated answer int m_ansStart; //Index of ans in expression int m_ansLength; bool m_ansVaild; bool m_curInAns; bool m_curOnAnsLeft; QString m_oldText; bool isSymbolCategoryChanged(int pos1, int pos2); int findWordBeginPosition(int pos); int findWordEndPosition(int pos); void heilightAns(int start, int length); }; #endif deepin-calculator-1.0.2/src/listview.cpp000066400000000000000000000144671325241207700202650ustar00rootroot00000000000000#include "listview.h" #include "dthememanager.h" #include "utils.h" #include #include #include DWIDGET_USE_NAMESPACE ListView::ListView(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_TranslucentBackground); rowHeight = 35; padding = 10; offset = 0; scrollbarMinHeight = 30; isPress = false; isShowScrollbar = false; setMouseTracking(true); setMinimumHeight(105); initTheme(); connect(DThemeManager::instance(), &DThemeManager::themeChanged, this, [=] { initTheme(); }); } ListView::~ListView() { } void ListView::initTheme() { if (DThemeManager::instance()->theme() == "light") { backgroundColor = "#FBFBFB"; fontColor = "#636363"; errorFontColor = "#F37D54"; scrollbarColor = "#000000"; } else { backgroundColor = "#111111"; fontColor = "#C3C3C3"; errorFontColor = "#F37D54"; scrollbarColor = "#FFFFFF"; } } void ListView::addItem(const QString &text) { for (const QString &itemStr : listItems) { if (itemStr == text) { listItems.removeAt(listItems.indexOf(itemStr)); } } listItems << text; scrollToBottom(); } void ListView::clearItems() { listItems.clear(); scrollToBottom(); } void ListView::scrollToBottom() { offset = getItemsTotalHeight() - rect().height(); update(); } int ListView::getItemsCount() { return listItems.count(); } void ListView::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); // Draw Items. painter.setFont(QFont("Noto Sans CJK SC")); painter.setPen(QColor(fontColor)); const int rightPadding = padding + 15; int drawHeight = 0; int count = 0; for (QString item : listItems) { if (count >= offset / rowHeight) { QStringList list = item.split("="); QString resultStr = list.last(); int resultWidth = fontMetrics().width(resultStr); QRect itemRect(padding, count * rowHeight - offset, rect().width(), rowHeight); if (resultWidth > rect().width() / 1.3) { resultStr = fontMetrics().elidedText(resultStr, Qt::ElideRight, rect().width() / 1.3); resultWidth = fontMetrics().width(resultStr); } QString expStr = fontMetrics().elidedText(list.first(), Qt::ElideLeft, rect().width() - resultWidth - rightPadding * 2); // Check whether result text is digit. if (Utils::stringIsDigit(list.last())) { painter.setPen(QColor(fontColor)); } else { painter.setPen(QColor(errorFontColor)); } // Draw result text. painter.drawText(QRect(itemRect.x(), itemRect.y(), itemRect.width() - rightPadding, itemRect.height()), Qt::AlignVCenter | Qt::AlignRight, resultStr); // Draw expression text. painter.setPen(QColor(fontColor)); painter.drawText(QRect(itemRect.x(), itemRect.y(), itemRect.width() - rightPadding - resultWidth, itemRect.height()), Qt::AlignVCenter | Qt::AlignRight, expStr + " = "); drawHeight += rowHeight; if (drawHeight > rect().height()) break; } ++count; } // Draw scrollbar if (!isShowScrollbar) return; painter.setBrush(QColor(scrollbarColor)); if (isPress) { painter.setOpacity(0.7); } else { painter.setOpacity(0.5); } if (getItemsTotalHeight() > rect().height()) { const int radius = 4; painter.drawRoundedRect(QRect(rect().width() - 9, getScrollbarY(), 6, getScrollbarHeight()), radius, radius); } } void ListView::mouseMoveEvent(QMouseEvent *e) { bool isShowbar = getItemsTotalHeight() > rect().height(); if (isShowbar) { if (isPress) { offset = adjustOffset((e->y() - getScrollbarHeight() / 2) / (rect().height() * 1.0) * getItemsTotalHeight()); isShowScrollbar = true; update(); } else if (e->x() > getScrollbarX()) { isShowScrollbar = true; update(); } else { if (isShowScrollbar) { isShowScrollbar = false; update(); } } } if (!isShowbar || e->x() < getScrollbarX() && !isPress) { QWidget::mouseMoveEvent(e); } } void ListView::mousePressEvent(QMouseEvent *e) { if (getItemsTotalHeight() > rect().height()) { if (e->x() > getScrollbarX()) { isPress = true; offset = adjustOffset((e->y() - getScrollbarHeight() / 2) / (rect().height() * 1.0) * getItemsTotalHeight()); update(); } } } void ListView::mouseReleaseEvent(QMouseEvent *e) { if (isPress) { isPress = false; } update(); } void ListView::wheelEvent(QWheelEvent *e) { if (getItemsTotalHeight() < rect().height()) { return; } if (e->orientation() == Qt::Vertical) { qreal scrollStep = e->angleDelta().y() / 120.0; offset = adjustOffset(offset - scrollStep * rowHeight); isShowScrollbar = true; update(); } e->accept(); } void ListView::leaveEvent(QEvent *) { isShowScrollbar = false; update(); } int ListView::getItemsTotalHeight() { return listItems.count() * rowHeight; } int ListView::getScrollbarHeight() { return (rect().height() * 1.0) / getItemsTotalHeight() * rect().height(); //return qMax(scrollbarMinHeight, static_cast(rect().height() * 1.0 / getItemsTotalHeight() * rect().height())); } int ListView::getScrollbarX() { return rect().width() - 10; } int ListView::getScrollbarY() { return offset / (getItemsTotalHeight() * 1.0) * rect().height(); } int ListView::adjustOffset(const int &offset) { return qMax(0, qMin(offset, getItemsTotalHeight() - rect().height())); } deepin-calculator-1.0.2/src/listview.h000066400000000000000000000017301325241207700177170ustar00rootroot00000000000000#ifndef LISTVIEW_H #define LISTVIEW_H #include class ListView : public QWidget { Q_OBJECT public: ListView(QWidget *parent = nullptr); ~ListView(); void initTheme(); void addItem(const QString &text); void clearItems(); void scrollToBottom(); int getItemsCount(); protected: void paintEvent(QPaintEvent *); void mouseMoveEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void wheelEvent(QWheelEvent *); void leaveEvent(QEvent *); int getItemsTotalHeight(); int getScrollbarHeight(); int getScrollbarX(); int getScrollbarY(); int adjustOffset(const int &offset); private: QList listItems; int rowHeight; int padding; int offset; int scrollbarMinHeight; bool isPress; bool isShowScrollbar; QString backgroundColor; QString fontColor; QString errorFontColor; QString scrollbarColor; }; #endif deepin-calculator-1.0.2/src/main.cpp000066400000000000000000000017641325241207700173370ustar00rootroot00000000000000#include #include #include #include "mainwindow.h" DWIDGET_USE_NAMESPACE int main(int argc, char *argv[]) { DApplication::loadDXcbPlugin(); DApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps); app.loadTranslator(); app.setOrganizationName("deepin"); app.setApplicationVersion(DApplication::buildVersion("1.0.1")); app.setApplicationAcknowledgementPage("https://www.deepin.org/acknowledgments/deepin-calculator"); app.setProductIcon(QIcon(":/images/deepin-calculator.svg")); app.setProductName(DApplication::translate("Main", "Deepin Calculator")); app.setApplicationDescription(DApplication::translate("Main", "Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division.")); MainWindow w; w.show(); if (app.setSingleInstance("deepin-calculator")) { Dtk::Widget::moveToCenter(&w); } return app.exec(); } deepin-calculator-1.0.2/src/mainwindow.cpp000066400000000000000000000247761325241207700205770ustar00rootroot00000000000000#include "mainwindow.h" #include "dthememanager.h" #include "dtitlebar.h" #include "utils.h" #include #include #include #include MainWindow::MainWindow(DMainWindow *parent) : DMainWindow(parent) { m_mainWidget = new QWidget; m_mainLayout = new QGridLayout(m_mainWidget); m_settings = new DSettings; m_expList = new ExpressionList; clearButton = new TextButton("C"); backButton = new BackButton; modButton = new TextButton("%"); divButton = new TextButton("÷"); num7Button = new TextButton("7"); num8Button = new TextButton("8"); num9Button = new TextButton("9"); multButton = new TextButton("×"); num4Button = new TextButton("4"); num5Button = new TextButton("5"); num6Button = new TextButton("6"); minButton = new TextButton("-"); num1Button = new TextButton("1"); num2Button = new TextButton("2"); num3Button = new TextButton("3"); plusButton = new TextButton("+"); zeroButton = new TextButton("0"); pointButton = new TextButton("."); bracketsButton = new TextButton("( )"); equalButton = new TextButton("="); m_mainLayout->addWidget(m_expList, 0, 0, 1, 4); m_mainLayout->addWidget(clearButton, 2, 0); m_mainLayout->addWidget(modButton, 2, 1); m_mainLayout->addWidget(backButton, 2, 2); m_mainLayout->addWidget(divButton, 2, 3); m_mainLayout->addWidget(num7Button, 3, 0); m_mainLayout->addWidget(num8Button, 3, 1); m_mainLayout->addWidget(num9Button, 3, 2); m_mainLayout->addWidget(multButton, 3, 3); m_mainLayout->addWidget(num4Button, 4, 0); m_mainLayout->addWidget(num5Button, 4, 1); m_mainLayout->addWidget(num6Button, 4, 2); m_mainLayout->addWidget(minButton, 4, 3); m_mainLayout->addWidget(num1Button, 5, 0); m_mainLayout->addWidget(num2Button, 5, 1); m_mainLayout->addWidget(num3Button, 5, 2); m_mainLayout->addWidget(plusButton, 5, 3); m_mainLayout->addWidget(zeroButton, 6, 0); m_mainLayout->addWidget(pointButton, 6, 1); m_mainLayout->addWidget(bracketsButton, 6, 2); m_mainLayout->addWidget(equalButton, 6, 3); m_mainLayout->setMargin(0); m_mainLayout->setSpacing(1); divButton->setObjectName("SymbolButton"); multButton->setObjectName("SymbolButton"); minButton->setObjectName("SymbolButton"); plusButton->setObjectName("SymbolButton"); equalButton->setObjectName("EqualButton"); if (titlebar()) { m_menu = new QMenu; m_themeAction = new QAction(tr("Dark Theme"), this); m_themeAction->setCheckable(true); m_menu->addAction(m_themeAction); m_menu->addSeparator(); QLabel *icon = new QLabel; icon->setPixmap(DHiDPIHelper::loadNxPixmap(":/images/title_icon.svg")); titlebar()->setMenu(m_menu); titlebar()->setFixedHeight(30); titlebar()->setCustomWidget(icon, Qt::AlignVCenter, false); #if DTK_VERSION >= 0x02000600 titlebar()->setBackgroundTransparent(true); #endif initTheme(); initThemeAction(); connect(m_themeAction, &QAction::triggered, this, &MainWindow::switchTheme); } setWindowIcon(QIcon(":/images/deepin-calculator.svg")); setWindowTitle(tr("Deepin Calculator")); setCentralWidget(m_mainWidget); if (m_settings->getOption("Resize").toBool()) { resize(322, 495); } else { setFixedSize(322, 495); } connect(zeroButton, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num1Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num2Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num3Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num4Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num5Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num6Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num7Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num8Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(num9Button, &QPushButton::clicked, this, &MainWindow::onNumberButtonClicked); connect(plusButton, &QPushButton::clicked, this, &MainWindow::onSymbolButtonClicked); connect(minButton, &QPushButton::clicked, this, &MainWindow::onSymbolButtonClicked); connect(multButton, &QPushButton::clicked, this, &MainWindow::onSymbolButtonClicked); connect(divButton, &QPushButton::clicked, this, &MainWindow::onSymbolButtonClicked); connect(modButton, &QPushButton::clicked, this, &MainWindow::onSymbolButtonClicked); connect(bracketsButton, &QPushButton::clicked, m_expList, &ExpressionList::enterBracketsEvent); connect(equalButton, &QPushButton::clicked, m_expList, &ExpressionList::enterEqualEvent); connect(clearButton, &QPushButton::clicked, m_expList, &ExpressionList::enterClearEvent); connect(backButton, &QPushButton::clicked, m_expList, &ExpressionList::enterBackspaceEvent); connect(pointButton, &QPushButton::clicked, m_expList, &ExpressionList::enterPointEvent); connect(m_expList, &ExpressionList::clearStateChanged, this, &MainWindow::clearButtonStateChanged); connect(m_expList, &ExpressionList::inputKeyPressEvent, this, &MainWindow::keyPressEvent); } MainWindow::~MainWindow() { // We don't need clean pointers because applicatibon has exit here. } void MainWindow::paintEvent(QPaintEvent * event) { DMainWindow::paintEvent(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(Qt::NoPen); // Draw titlebar background color. painter.setBrush(QColor(m_titlebarColor)); painter.drawRect(rect()); // Draw separator line. painter.setBrush(QColor(m_separatorColor)); painter.drawRect(QRect(0, titlebar()->height() + m_expList->height(), width(), 1)); const int buttonsTotalHeight = height() - titlebar()->height() - m_expList->height(); painter.setBrush(m_backgroundColor); painter.drawRect(QRect(0, height() - buttonsTotalHeight + 1, width(), buttonsTotalHeight)); } void MainWindow::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_0: m_expList->enterNumberEvent(nullptr, true); zeroButton->animate(); break; case Qt::Key_1: m_expList->enterNumberEvent(nullptr, true); num1Button->animate(); break; case Qt::Key_2: m_expList->enterNumberEvent(nullptr, true); num2Button->animate(); break; case Qt::Key_3: m_expList->enterNumberEvent(nullptr, true); num3Button->animate(); break; case Qt::Key_4: m_expList->enterNumberEvent(nullptr, true); num4Button->animate(); break; case Qt::Key_5: m_expList->enterNumberEvent(nullptr, true); num5Button->animate(); break; case Qt::Key_6: m_expList->enterNumberEvent(nullptr, true); num6Button->animate(); break; case Qt::Key_7: m_expList->enterNumberEvent(nullptr, true); num7Button->animate(); break; case Qt::Key_8: m_expList->enterNumberEvent(nullptr, true); num8Button->animate(); break; case Qt::Key_9: m_expList->enterNumberEvent(nullptr, true); num9Button->animate(); break; case Qt::Key_Plus: plusButton->animateClick(); break; case Qt::Key_Minus: case Qt::Key_Underscore: minButton->animateClick(); break; case Qt::Key_Asterisk: case Qt::Key_X: multButton->animateClick(); break; case Qt::Key_Slash: divButton->animateClick(); break; case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Equal: equalButton->animateClick(); break; case Qt::Key_Backspace: if (!m_expList->getInputEditText().isEmpty()) { backButton->animate(); } break; case Qt::Key_Period: pointButton->animateClick(); break; case Qt::Key_Escape: clearButton->animateClick(); break; case Qt::Key_ParenLeft: case Qt::Key_ParenRight: m_expList->setContinue(true); bracketsButton->animate(); break; case Qt::Key_Percent: modButton->animateClick(); break; case Qt::Key_C: if (e->modifiers() == Qt::ControlModifier) { m_expList->copyResultToClipboard(); } break; } } void MainWindow::resizeEvent(QResizeEvent *) { m_expList->update(); } void MainWindow::initTheme() { QString theme = m_settings->getOption("theme").toString(); DThemeManager::instance()->setTheme(theme); const bool isBlur = m_settings->getOption("EnableBlur").toBool(); if (isBlur) { setAttribute(Qt::WA_TranslucentBackground); setEnableBlurWindow(true); titlebar()->setAttribute(Qt::WA_TranslucentBackground); } if (theme == "light") { this->setStyleSheet(Utils::getQssContent(":/qss/light.qss")); m_titlebarColor = isBlur ? QColor(251,251,251, 0.6 * 255) : QColor(251,251,251); m_separatorColor = "#E1E1E1"; m_backgroundColor = QColor(0, 0, 0, 0.05 * 255); } else { this->setStyleSheet(Utils::getQssContent(":/qss/dark.qss")); m_titlebarColor = isBlur ? QColor(17, 17, 17, 0.6 * 255) : QColor(17, 17, 17); m_separatorColor = "#303030"; m_backgroundColor = QColor("#2D2D2D"); } } void MainWindow::initThemeAction() { m_themeAction->setChecked(m_settings->getOption("theme") == "dark"); } void MainWindow::switchTheme() { const QString theme = m_settings->getOption("theme").toString(); if (m_settings->getOption("theme") == "dark") { m_settings->setOption("theme", "light"); initTheme(); } else { m_settings->setOption("theme", "dark"); initTheme(); } } void MainWindow::onNumberButtonClicked() { QPushButton *btn = qobject_cast(sender()); if (!btn) { return; } m_expList->enterNumberEvent(btn->text()); } void MainWindow::onSymbolButtonClicked() { QPushButton *btn = qobject_cast(sender()); if (!btn) { return; } m_expList->enterSymbolEvent(btn->text()); } void MainWindow::clearButtonStateChanged(bool isAllClear) { if (isAllClear) { if (m_expList->getItemsCount() > 0) { clearButton->setText("AC"); } } else { clearButton->setText("C"); } } deepin-calculator-1.0.2/src/mainwindow.h000066400000000000000000000030121325241207700202200ustar00rootroot00000000000000#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include "expressionlist.h" #include "textbutton.h" #include "backbutton.h" #include "dsettings.h" DWIDGET_USE_NAMESPACE class MainWindow : public DMainWindow { Q_OBJECT public: MainWindow(DMainWindow *parent = nullptr); ~MainWindow(); protected: void paintEvent(QPaintEvent *); void keyPressEvent(QKeyEvent *); void resizeEvent(QResizeEvent *); private slots: void initTheme(); void initThemeAction(); void switchTheme(); void onNumberButtonClicked(); void onSymbolButtonClicked(); void clearButtonStateChanged(bool isAllClear); private: QWidget *m_mainWidget; QMenu *m_menu; QAction *m_themeAction; DSettings *m_settings; QGridLayout *m_mainLayout; ExpressionList *m_expList; TextButton *clearButton; BackButton *backButton; TextButton *modButton; TextButton *divButton; TextButton *num7Button; TextButton *num8Button; TextButton *num9Button; TextButton *multButton; TextButton *num4Button; TextButton *num5Button; TextButton *num6Button; TextButton *minButton; TextButton *num1Button; TextButton *num2Button; TextButton *num3Button; TextButton *plusButton; TextButton *zeroButton; TextButton *pointButton; TextButton *bracketsButton; TextButton *equalButton; QColor m_titlebarColor; QColor m_separatorColor; QColor m_backgroundColor; }; #endif deepin-calculator-1.0.2/src/textbutton.cpp000066400000000000000000000041241325241207700206240ustar00rootroot00000000000000#include "textbutton.h" #include "dthememanager.h" #include DWIDGET_USE_NAMESPACE TextButton::TextButton(const QString &text, QWidget *parent) : QPushButton(text, parent) { m_effect = new QGraphicsDropShadowEffect(this); setMinimumSize(80, 60); setMouseTracking(true); setFocusPolicy(Qt::NoFocus); setObjectName("TextButton"); setGraphicsEffect(m_effect); initShadow(); hideShadowEffect(); connect(DThemeManager::instance(), &DThemeManager::themeChanged, this, [=] { initShadow(); }); } TextButton::~TextButton() { delete m_effect; } void TextButton::showShadowEffect() { m_effect->setEnabled(true); raise(); } void TextButton::hideShadowEffect() { m_effect->setEnabled(false); } void TextButton::animate(int msec) { setDown(true); QTimer::singleShot(msec, this, [=] { setDown(false); }); } void TextButton::initShadow() { if (DThemeManager::instance()->theme() == "light") { m_effect->setColor(QColor(12, 155, 246, 255 * 0.1)); m_effect->setXOffset(0); m_effect->setYOffset(4); m_effect->setBlurRadius(12); if (text() == "=") { m_effect->setColor(QColor(12, 155, 246, 255 * 0.8)); m_effect->setBlurRadius(20); } } else { m_effect->setColor(QColor(0, 0, 0, 255 * 0.1)); m_effect->setXOffset(0); m_effect->setYOffset(4); m_effect->setBlurRadius(12); if (text() == "=") { m_effect->setColor(QColor(12, 155, 246, 255 * 0.6)); m_effect->setBlurRadius(30); m_effect->setXOffset(-2); m_effect->setYOffset(-4); } } } void TextButton::mousePressEvent(QMouseEvent *e) { hideShadowEffect(); QPushButton::mousePressEvent(e); } void TextButton::mouseReleaseEvent(QMouseEvent *e) { showShadowEffect(); QPushButton::mouseReleaseEvent(e); } void TextButton::enterEvent(QEvent *e) { showShadowEffect(); QPushButton::enterEvent(e); } void TextButton::leaveEvent(QEvent *e) { hideShadowEffect(); QPushButton::leaveEvent(e); } deepin-calculator-1.0.2/src/textbutton.h000066400000000000000000000011401325241207700202640ustar00rootroot00000000000000#ifndef TEXTBUTTON_H #define TEXTBUTTON_H #include #include class TextButton : public QPushButton { Q_OBJECT public: TextButton(const QString &text = QString(), QWidget *parent = nullptr); ~TextButton(); void showShadowEffect(); void hideShadowEffect(); void animate(int msec = 100); protected: void initShadow(); void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void enterEvent(QEvent *); void leaveEvent(QEvent *); private: QGraphicsDropShadowEffect *m_effect; }; #endif deepin-calculator-1.0.2/src/utils.cpp000066400000000000000000000032441325241207700175460ustar00rootroot00000000000000#include "utils.h" #include #include Utils::Utils() { } Utils::~Utils() { } QString Utils::getQssContent(const QString &filePath) { QFile file(filePath); QString qss = nullptr; if (file.open(QIODevice::ReadOnly)) { qss = file.readAll(); } return qss; } QString Utils::formatThousandsSeparators(const QString &str) { QString result = str; int startPos = result.indexOf(QRegularExpression("[0-9]")); if (startPos >= 0) { int endPos = result.indexOf('.'); if (endPos < 0) { endPos = result.length(); } for (int i = endPos - 3; i >= startPos + 1; i -= 3) { result.insert(i, ","); } } return result; } bool Utils::stringIsDigit(const QString &str) { bool isDigit = true; for (auto &ch : str) { if (!ch.isDigit() && ch != '.' && ch != ',' && ch != '-') { isDigit = false; break; } } return isDigit; } QString Utils::reformatSeparators(const QString &exp) { QString seg; QStringList expList; int count = 0; for (auto ch : exp) { if (ch.isDigit() || ch == '.') { seg.append(ch); } else { expList << seg; seg.clear(); seg.append(ch); expList << seg; seg.clear(); } if (count == exp.count() - 1) { expList << seg; } ++count; } QString formatStr; for (auto item : expList) { if (stringIsDigit(item)) { item = formatThousandsSeparators(item); } formatStr.append(item); } return formatStr; } deepin-calculator-1.0.2/src/utils.h000066400000000000000000000005741325241207700172160ustar00rootroot00000000000000#ifndef UTILS_H #define UTILS_H #include class Utils : public QObject { Q_OBJECT public: Utils(); ~Utils(); static QString getQssContent(const QString &filePath); static QString formatThousandsSeparators(const QString &str); static bool stringIsDigit(const QString &str); static QString reformatSeparators(const QString &exp); }; #endif deepin-calculator-1.0.2/translations.pri000066400000000000000000000026411325241207700203500ustar00rootroot00000000000000TRANSLATIONS += translations/deepin-calculator.ts \ translations/deepin-calculator_af.ts \ translations/deepin-calculator_am_ET.ts \ translations/deepin-calculator_ar.ts \ translations/deepin-calculator_bg.ts \ translations/deepin-calculator_ca.ts \ translations/deepin-calculator_cs.ts \ translations/deepin-calculator_da.ts \ translations/deepin-calculator_de.ts \ translations/deepin-calculator_es.ts \ translations/deepin-calculator_es_419.ts \ translations/deepin-calculator_fr.ts \ translations/deepin-calculator_he.ts \ translations/deepin-calculator_hr.ts \ translations/deepin-calculator_hu.ts \ translations/deepin-calculator_it.ts \ translations/deepin-calculator_lt.ts \ translations/deepin-calculator_pl.ts \ translations/deepin-calculator_pt.ts \ translations/deepin-calculator_pt_BR.ts \ translations/deepin-calculator_ru.ts \ translations/deepin-calculator_sk.ts \ translations/deepin-calculator_sl.ts \ translations/deepin-calculator_tr.ts \ translations/deepin-calculator_zh_CN.ts \ translations/deepin-calculator_zh_TW.ts deepin-calculator-1.0.2/translations/000077500000000000000000000000001325241207700176315ustar00rootroot00000000000000deepin-calculator-1.0.2/translations/deepin-calculator.ts000066400000000000000000000016751325241207700236050ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator Dark Theme deepin-calculator-1.0.2/translations/deepin-calculator_af.ts000066400000000000000000000015751325241207700242520ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator Dark Theme Donker Tema deepin-calculator-1.0.2/translations/deepin-calculator_am_ET.ts000066400000000000000000000021561325241207700246450ustar00rootroot00000000000000 ExpressionList Expression Error የ አገላለጽ ስህተት Main Deepin Calculator ዲፕኢን ማስሊያ Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. የ ዲፕኢን ማስሊያ ለ መጠቀም በጣም ቀላል ነው: የሚያስችለውም መደመር: መቀነስ: ማባዛት: እና ማካፈል ነው MainWindow Deepin Calculator ዲፕኢን ማስሊያ Dark Theme ጥቁር ገጽታ deepin-calculator-1.0.2/translations/deepin-calculator_ar.ts000066400000000000000000000021341325241207700242560ustar00rootroot00000000000000 ExpressionList Expression Error خطأ في المصطح Main Deepin Calculator حاسبة ديبين Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. حاسبة ديبين : إنها بسيطة وسهلة لاستخدمات سطح المكتب ، تدعم عمليات الجمع والطرح والضرب والقسمة. MainWindow Deepin Calculator حاسبة ديبين Dark Theme سمة داكنة deepin-calculator-1.0.2/translations/deepin-calculator_ast.ts000066400000000000000000000020561325241207700244460ustar00rootroot00000000000000 ExpressionList Expression Error Fallu d'espresión Main Deepin Calculator Deepin Calculator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Calculator ye una calculadora d'escritoriu cenciella y fácil d'usar. Sofita sumes, restes, multiplicaciones y divisiones. MainWindow Deepin Calculator Deepin Calculator Dark Theme Tema escuru deepin-calculator-1.0.2/translations/deepin-calculator_bg.ts000066400000000000000000000021671325241207700242520ustar00rootroot00000000000000 ExpressionList Expression Error Грешен Израз Main Deepin Calculator Deepin Калкулатор Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Калкулатор е прост и лесен десктоп калкулатор. Поддържа събиране, изваждане, умножение и деление. MainWindow Deepin Calculator Deepin Калкулатор Dark Theme Тъмна тема deepin-calculator-1.0.2/translations/deepin-calculator_bn.ts000066400000000000000000000024521325241207700242560ustar00rootroot00000000000000 ExpressionList Expression Error ত্রুটিপূর্ণ সমীকরণ Main Deepin Calculator ডিপিন ক্যালকুলেটর Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. ডিপিন ক্যালকুলেটর একটি সাধারণ সহজে ব্যবহার যোগ্য ডেস্কটপ ক্যালকুলেটর। এটা যোগ, বিয়োগ, গুণ এবং ভাগ করতে পারে। MainWindow Deepin Calculator ডিপিন ক্যালকুলেটর Dark Theme কালো থীম deepin-calculator-1.0.2/translations/deepin-calculator_ca.ts000066400000000000000000000020761325241207700242440ustar00rootroot00000000000000 ExpressionList Expression Error Error d'expressió Main Deepin Calculator Calculadora del Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. La calculadora del Deepin és una calculadora d'escriptori senzilla i fàcil d'usar. Admet sumar, restar, multiplicar i dividir amb resta. MainWindow Deepin Calculator Calculadora del Deepin Dark Theme Tema fosc deepin-calculator-1.0.2/translations/deepin-calculator_cs.ts000066400000000000000000000017771325241207700242750ustar00rootroot00000000000000 ExpressionList Expression Error Chyba ve výrazu Main Deepin Calculator Kalkulačka Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Kalkulačka je jednoduchá a snadno použitelná. Podporuje sčítání, odečítání, násobení a dělení. MainWindow Deepin Calculator Kalkulačka Dark Theme Tmavý vzhled deepin-calculator-1.0.2/translations/deepin-calculator_da.ts000066400000000000000000000020501325241207700242350ustar00rootroot00000000000000 ExpressionList Expression Error Fejl i udtryk Main Deepin Calculator Deepin lommeregner Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin lommeregner er en simpel og let anvendelig skrivebordslommeregner. Den understøtter addition, subtraktion, multiplikation og division. MainWindow Deepin Calculator Deepin lommeregner Dark Theme Mørkt tema deepin-calculator-1.0.2/translations/deepin-calculator_de.ts000066400000000000000000000020601325241207700242420ustar00rootroot00000000000000 ExpressionList Expression Error Ungültiger Ausdruck Main Deepin Calculator Deepin Taschenrechner Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Der Deepin Taschenrechner ist ein einfacher Desktop-Taschenrechner. Er unterstützt Addition, Subtraktion, Multiplikation und Division. MainWindow Deepin Calculator Deepin Taschenrechner Dark Theme Dunkles Theme deepin-calculator-1.0.2/translations/deepin-calculator_es.ts000066400000000000000000000020631325241207700242640ustar00rootroot00000000000000 ExpressionList Expression Error Error de expresión Main Deepin Calculator Calculadora Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Calculator es una calculadora de escritorio simple y fácil de usar. Es compatible con la suma, la resta, la multiplicación y la división. MainWindow Deepin Calculator Calculadora Deepin Dark Theme Tema oscuro deepin-calculator-1.0.2/translations/deepin-calculator_es_419.ts000066400000000000000000000016561325241207700246700ustar00rootroot00000000000000 ExpressionList Expression Error Error de expresión Main Deepin Calculator Calculadora Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. <br> MainWindow Deepin Calculator Calculadora Deepin Dark Theme Tema oscuro deepin-calculator-1.0.2/translations/deepin-calculator_fa.ts000066400000000000000000000021531325241207700242430ustar00rootroot00000000000000 ExpressionList Expression Error خطای بیان Main Deepin Calculator ماشین حساب دیپین Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. ماشین حساب Deepin یک ماشین حساب دسکتاپ ساده و آسان است. و از جمع، تفریق، ضرب و تقسیم پشتیبانی میکند. MainWindow Deepin Calculator ماشین حساب دیپین Dark Theme پوسته تیره deepin-calculator-1.0.2/translations/deepin-calculator_fr.ts000066400000000000000000000021171325241207700242640ustar00rootroot00000000000000 ExpressionList Expression Error Formule erronée Main Deepin Calculator Calculatrice Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Calculatrice Deepin est une calculatrice de bureau simple et facile à utiliser. Elle prend en charge les additions, les soustractions, les multiplications et les divisions. MainWindow Deepin Calculator Calculatrice Deepin Dark Theme Thème sombre deepin-calculator-1.0.2/translations/deepin-calculator_gl_ES.ts000066400000000000000000000020501325241207700246420ustar00rootroot00000000000000 ExpressionList Expression Error Erro na expresión Main Deepin Calculator Calculadora Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Calculadora é unha ferramenta simple e sinxela para realizar operacións de escritorio. Pode realizar sumas, restas, multiplicacións e divisións. MainWindow Deepin Calculator Calculadora Dark Theme Tema Escuro deepin-calculator-1.0.2/translations/deepin-calculator_he.ts000066400000000000000000000016661325241207700242610ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator המחשבון של Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator המחשבון של Deepin Dark Theme ערכת עיצוב כהה deepin-calculator-1.0.2/translations/deepin-calculator_hr.ts000066400000000000000000000016241325241207700242700ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator Deepin kalkukator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator Deepin kalkukator Dark Theme Tamna tema deepin-calculator-1.0.2/translations/deepin-calculator_hu.ts000066400000000000000000000020651325241207700242730ustar00rootroot00000000000000 ExpressionList Expression Error Kifejezéshiba Main Deepin Calculator Deepin Számológép Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. A Deepin Számológép egy könnyen használható számológép alkalmazás. Tartalmazza az összes alapműveletet és egy kicsit többet is annál. MainWindow Deepin Calculator Deepin számológép Dark Theme Sötét téma deepin-calculator-1.0.2/translations/deepin-calculator_id.ts000066400000000000000000000020441325241207700242500ustar00rootroot00000000000000 ExpressionList Expression Error Kesalahan Ekspresi Main Deepin Calculator Kalkulator Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Kalkulator Deepin adalah kalkulator desktop yang sederhana dan mudah. Dengan dukungan pertambahan, pengurangan, perkalian dan pembagian. MainWindow Deepin Calculator Kalkulator Deepin Dark Theme Tema Gelap deepin-calculator-1.0.2/translations/deepin-calculator_it.ts000066400000000000000000000021371325241207700242730ustar00rootroot00000000000000 ExpressionList Expression Error Errore dell'espressione Main Deepin Calculator Deepin Calculator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Calculator è una calcolatrice semplice e facile da usare. Supporta le somme, le sottrazioni, moltiplicazioni e divisioni. Localizzazione italiana a cura di Massimo A. Carofano. MainWindow Deepin Calculator Deepin Calculator Dark Theme Tema scuro deepin-calculator-1.0.2/translations/deepin-calculator_lt.ts000066400000000000000000000016341325241207700242770ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator Deepin skaičiuotuvas Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator Deepin skaičiuotuvas Dark Theme Tamsi tema deepin-calculator-1.0.2/translations/deepin-calculator_ms.ts000066400000000000000000000020351325241207700242730ustar00rootroot00000000000000 ExpressionList Expression Error Ralat Ungkapan Main Deepin Calculator Kalkulator Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Kalkulator Deepin merupakan kalkulator desktop yang ringkas dan mudah digunakan. Ia menyokong fungsi tambah, tolak, darab dan bahagi. MainWindow Deepin Calculator Kalkulator Deepin Dark Theme Tema Gelap deepin-calculator-1.0.2/translations/deepin-calculator_nl.ts000066400000000000000000000020631325241207700242660ustar00rootroot00000000000000 ExpressionList Expression Error Uitdrukking fout Main Deepin Calculator Deepin Rekenmachine Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Rekenmachine is een eenvoudige en gebruiksvriendelijke desktop rekenmachine. Het ondersteunt optellen, aftrekken, vermenigvuldigen en delen. MainWindow Deepin Calculator Deepin Rekenmachine Dark Theme Donker Thema deepin-calculator-1.0.2/translations/deepin-calculator_pl.ts000066400000000000000000000020621325241207700242670ustar00rootroot00000000000000 ExpressionList Expression Error Błąd wyrażenia matematycznego Main Deepin Calculator Kalkulator Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Kalkulator Deepin to prosty i łatwy w użyciu kalkulator biurkowy. Obsługuje operacje dodawania, odejmowania, mnożenia i dzielenia. MainWindow Deepin Calculator Kalkulator Deepin Dark Theme Motyw ciemny deepin-calculator-1.0.2/translations/deepin-calculator_pt.ts000066400000000000000000000020331325241207700242750ustar00rootroot00000000000000 ExpressionList Expression Error Erro de Expressão Main Deepin Calculator Deepin Calculator Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. A Deepin Calculator é uma calculadora de ambiente de trabalho simples. Suporta soma, subtração, multiplicação e divisão. MainWindow Deepin Calculator Deepin Calculator Dark Theme Tema Escuro deepin-calculator-1.0.2/translations/deepin-calculator_pt_BR.ts000066400000000000000000000020731325241207700246640ustar00rootroot00000000000000 ExpressionList Expression Error Erro de expressão Main Deepin Calculator Calculadora Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Calculadora Deepin é uma calculadora simples e fácil de usar no desktop. Ela suporta operações como adição, subtração, multiplicação e divisão. MainWindow Deepin Calculator Calculadora Deepin Dark Theme Tema dark deepin-calculator-1.0.2/translations/deepin-calculator_ro.ts000066400000000000000000000020601325241207700242720ustar00rootroot00000000000000 ExpressionList Expression Error Eroare expresie Main Deepin Calculator Calculatorul Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Calculatorul Deepin este un calculator simplu și ușor de folosit. Suportă operațiuni de adunare, scădere, înmulțire și împărțire. MainWindow Deepin Calculator Calculatorul Deepin Dark Theme Fundal întunecat deepin-calculator-1.0.2/translations/deepin-calculator_ru.ts000066400000000000000000000024051325241207700243030ustar00rootroot00000000000000 ExpressionList Expression Error Ошибка Выражения Main Deepin Calculator Калькулятор Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Калькулятор Deepin - простой и удобный настольный калькулятор. Deepin Calculator - простой и удобный настольный калькулятор. Он поддерживает сложение, вычитание, умножение и деление. MainWindow Deepin Calculator Калькулятор Deepin Dark Theme Темная Тема deepin-calculator-1.0.2/translations/deepin-calculator_sk.ts000066400000000000000000000020451325241207700242720ustar00rootroot00000000000000 ExpressionList Expression Error Chyba výrazu Main Deepin Calculator Deepin Kalkulačka Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Kalkulačka je jednoduchá a ľahko použiteľná desktopová kalkulačka. Podporuje sčítanie, odčítanie, násobenie a delenie. MainWindow Deepin Calculator Deepin Kalkulačka Dark Theme Tmavá téma deepin-calculator-1.0.2/translations/deepin-calculator_sl.ts000066400000000000000000000020061325241207700242700ustar00rootroot00000000000000 ExpressionList Expression Error Napaka v izrazu Main Deepin Calculator Kalkulator Deepin Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Kalkulator Deepin je preprost namizni kalkulator. Zmožen je seštevanja, odštevanja, množenja in deljenja. MainWindow Deepin Calculator Kalkulator Deepin Dark Theme Temna tema deepin-calculator-1.0.2/translations/deepin-calculator_tr.ts000066400000000000000000000020401325241207700242750ustar00rootroot00000000000000 ExpressionList Expression Error İfade Hatası Main Deepin Calculator Deepin Hesap Makinesi Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Hesap Makinesi basit ve kullanımı kolay masaüstü hesap makinesidir. Toplama, çıkarma, çarpma ve bölmeyi destekler. MainWindow Deepin Calculator Deepin Hesap Makinesi Dark Theme Koyu Tema deepin-calculator-1.0.2/translations/deepin-calculator_uk.ts000066400000000000000000000022441325241207700242750ustar00rootroot00000000000000 ExpressionList Expression Error Помилка вираження Main Deepin Calculator Deepin Калькулятор Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. Deepin Калькулятор це простий і зручний настільний калькулятор. Він підтримує додавання, віднімання, множення і ділення. MainWindow Deepin Calculator Deepin Калькулятор Dark Theme Темна тема deepin-calculator-1.0.2/translations/deepin-calculator_zh_CN.ts000066400000000000000000000017671325241207700246700ustar00rootroot00000000000000 ExpressionList Expression Error 表达式错误 Main Deepin Calculator 深度计算器 Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. 深度计算器是一款简单易用的桌面计算器,支持加、减、乘、除功能。 MainWindow Deepin Calculator 深度计算器 Dark Theme 深色主题 deepin-calculator-1.0.2/translations/deepin-calculator_zh_TW.ts000066400000000000000000000016271325241207700247150ustar00rootroot00000000000000 ExpressionList Expression Error Main Deepin Calculator Deepin 計算機 Deepin Calculator is a simple and easy to use desktop calculator. It supports addition, subtraction, multiplication and division. MainWindow Deepin Calculator Deepin 計算機 Dark Theme 深色模式 deepin-calculator-1.0.2/translations/translate_generation.sh000077500000000000000000000003511325241207700243770ustar00rootroot00000000000000#!/bin/bash # this file is used to auto-generate .qm file from .ts file. # author: shibowen at linuxdeepin.com ts_list=(`ls translations/*.ts`) for ts in "${ts_list[@]}" do printf "\nprocess ${ts}\n" lrelease "${ts}" done