Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122883 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id B59E21ADAAC for ; Tue, 2 Apr 2024 17:33:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712079248; bh=6zshG/Vm0Ca/tIMUYlZz1ZRqaczW+k7MrLJcJ4h78lI=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=k4SB003PyXYSyoYO5GpoLYXx7XRpg0K5GM36UbLDYUphkFPkJi4514NxsSjhDFRSH 72QxxbJtYG0HeBkHob6G2sDXZJ0Y7TJ+z0a0ZS/EmjCozWZbG7msC08nONZZKpjEcZ udhiuRrjwtuD7NZkGI19ELIQ1HHMtqZ6iRF+mJM7ELmmmtSma2ko9oO6j/ADCs+LX2 EPpj4vKIoD+R9+OPO94NxUgktIhWZfzl+jokJ+8esRnydqjunEXfdFHk2kigy3JYCO 5UzdLY11IIG/BhrU3W+ejc2i4mo41h6Lq6ugCJVm0lAmmrOBLI3r5gZDItCJjyT2CU G66rAQHpRBY+A== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3DFFB18075D for ; Tue, 2 Apr 2024 17:34:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.53]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 2 Apr 2024 17:34:03 +0000 (UTC) Received: by mail-pj1-f53.google.com with SMTP id 98e67ed59e1d1-29f93c4946cso3993217a91.1 for ; Tue, 02 Apr 2024 10:33:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1712079214; x=1712684014; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=6zshG/Vm0Ca/tIMUYlZz1ZRqaczW+k7MrLJcJ4h78lI=; b=gU9byR1BYasf5huUfpacrMTDPvlwxLrU2UL+eKqarkRQmnf2Q/9hZRphefLAClkybS bPgDZF35/DJxdMYyH4BWy3260TeJdwUlWmh7ohWtVsQpaNXIquB4I07ZDBee6NpD+x2d JNUmfyr3NwRLnjBCpbrz+ASkY9jKCXucZNREwHIyYjd4S3BIS02CjFwRTZamiYPjeOo4 IDDer0oDbhB++2BLKhUmQmn7BBB7A2uKvBoQBvwuMMamL3f/QQs/6GOiEr7vhn+eYCA1 BgFZCok+I2YKiYSNGOZYPLV5tbLE2bxoY96elmIZjITIy3JMpEHhN9SbJSr6k40PBa4+ eklA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712079214; x=1712684014; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=6zshG/Vm0Ca/tIMUYlZz1ZRqaczW+k7MrLJcJ4h78lI=; b=H+DIOn5dgSzeSg3amfaZ9TSbHaURsrbqkKGITg2w/M5Cvv8l5iRIgWo8rPeioREXOZ VwWYteBvWag9FEQm2pPXY0Jzd/ulGcHtjik21D3kDOl/aPduxGkZ++IMbZuCzcJAvejc QEAVFRq+HMOFwnD2FapkW+yUjACuqoM5nd2kDuhe8DGg7LHzEijMCXS29Y/7E0vUqYL8 fsafSrNVzaXJlVCTOgXPDBtAjCVO9LRVav8+606IZ8iaUZOMT2v83LAaI5Y87+FzoHYi oVNEbf/tf8A0b+GpEmiTMCu3hlh4voWnB6rCmXxrT8Q1w6w4vDZxLhB75TAmE1ke5MJX ImWQ== X-Forwarded-Encrypted: i=1; AJvYcCWTmBJBvF3/4UWV75CfhnZ97o+AJBTh+OzjD9anZda2s8cRUrm/RW6f4XQ3vt22nxjg0eUlEiv0muy1D1+6hnM/8AjVs7X4yg== X-Gm-Message-State: AOJu0YxSZyPi90GvtkHEPz6YCzlUFUezGBdS6iEkn1KLxA/LRUfEBaiX x8+5Yzt1myjdJ6YyqV93Jkx9IcnPI4Wzu/iSOYkSvSyR23PwZ4zucP7JxxGWSxFfamY8ZFk3O8t EO5Q8H7CfGCz5DU+Hk2/D7QEZ0u8= X-Google-Smtp-Source: AGHT+IERwO3yoVNKIkBZfkMecljo6cADJPP/G4fLwUSGeYUjlTo1e5STkJuScarh8meMRWHWoyfgZuPje9Q9jkgZ0n4= X-Received: by 2002:a17:90a:5909:b0:29d:e70f:7240 with SMTP id k9-20020a17090a590900b0029de70f7240mr11400913pji.11.1712079214097; Tue, 02 Apr 2024 10:33:34 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <4F094EDA-5058-407D-AF39-06FD934FDE1F@sakiot.com> <68CF373E-6ABF-4471-8992-813B4BA1B508@sakiot.com> <904197f4-afb5-401e-9e17-7a655c5449d0@alec.pl> In-Reply-To: Date: Tue, 2 Apr 2024 10:33:20 -0700 Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath To: Lynn Cc: Saki Takamachi , Aleksander Machniak , php internals Content-Type: multipart/alternative; boundary="0000000000006240bf06152081b2" From: jordan.ledoux@gmail.com (Jordan LeDoux) --0000000000006240bf06152081b2 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Apr 2, 2024 at 10:24=E2=80=AFAM Jordan LeDoux wrote: > > > On Tue, Apr 2, 2024 at 3:12=E2=80=AFAM Lynn wrote: > >> >> I'm inexperienced when it comes to maths and the precision here, but I d= o >> have some experience when it comes to what the business I work for wants= . >> I've implemented BCMath in a couple of places where this kind of precisi= on >> is necessary, and I found that whenever I do divisions I prefer having a= t >> least 2 extra digits. Would it make sense to internally always just stor= e a >> more accurate number? For things like >> additions/multiplications/subtractions it could always use the highest >> precision, and then for divisions add like +3~6 or something. Whenever y= ou >> have numbers that have a fraction like `10.5001` it makes sense to set i= t >> to 4, but when you have `10` it suddenly becomes 0 when implicitly setti= ng >> it. >> >> For the following examples assume each number is a BcNum: >> When doing something like `10 * 10.0000 * 10.000000000` I want the end >> result to have a precision of at least 9 so I don't lose information. Wh= en >> I do `((10 / 3) * 100) * 2` I don't want it to implicitly become 0, beca= use >> the precision here is important to me. I don't think using infinite >> precision here is a reasonable approach either. I'm not sure what the >> correct answer is, perhaps it's just "always manually set the precision"= ? >> > > In my library, if the scale is unspecified, I actually set the scale to 1= 0 > OR the length of the input string, including integer decimals, whichever = is > larger. Since I was designing my own library I could do things like that = as > convention, and a scale of 10 is extremely fast, even with the horrifical= ly > slow BCMath library, but covers most use cases (the overwhelmingly common > of which is exact calculation of money). > > My library handles scale using the following design. It's not necessarily > correct here, as I was designing a PHP library instead of something for > core, AND my library does not have to deal with operator overloads so I'm > always working with method signatures instead, AND it's possible that my > class/method design is inferior to other alternatives, however it went: > > 1. Each number constructor allowed for an optional input scale. > 2. The input number was converted into the proper formatting from allowed > input types, and then the implicit scale is set to the total number of > digits. > 3. If the input scale was provided, the determined scale is set to that > value. > 4. Otherwise, the determined scale at construction is set to 10 or the > implicit scale of "number of digits", whichever is larger. > 5. The class contained the `roundToScale` method, which allowed you to > provide the desired scale and the rounding method, and then would set the > determined scale to that value after rounding. It contained the `round` > method with the same parameters to allow rounding to a specific scale > without also setting the internal determined scale at the same time. > 6. The class contained the `setScale` method which set the value of the > internal determined scale value to an int without mutating the value at a= ll. > 7. All mathematical operation methods which depended on scale, (such as > div or pow), allowed an optional input scale that would be used for > calculation if present. If it was not present, the internal calculations > were done by taking the higher of the determined scale between the two > operands, and then adding 2, and then the result was done by rounding usi= ng > the default method of ROUND_HALF_EVEN if no rounding method was provided. > > Again, though I have spent a lot of design time on this issue for the mat= h > library I developed, my library did not have to deal with the RFC process > for PHP or maintain consistency with the conventions of PHP core, only wi= th > the conventions it set for itself. However, I can provide a link to the > library for reference on the issue if that would be helpful for people th= at > are contributing to the design aspects of this RFC. > > > The current assumption is that a Number always holds a single value. Ho= w > if we made it so that it held two values? They are the numerator and the > denominator. > > Again, my experience on the issue is with the development of my own > library on the issue, however in my case I fully separated that kind of > object into its own class `Fraction`, and gave the kinds of operations > we've been discussing to the class `Decimal`. Storing numerators and > denominators for as long as possible involves a completely different set = of > math. For instance, you need an algorithm to determine the Greatest Commo= n > Factor and the Least Common Multiple in such a class, because there are a > lot of places where you would need to find the smallest common denominato= r > or simplify the fraction. > > Abstracting between the `Fraction` and `Decimal` so that they worked with > each other honestly introduced the most complex and inscrutable code in m= y > entire library, so unless fractions are themselves also a design goal of > this RFC, I would recommend against it. > > Jordan > An addendum: Having two classes `Fraction` and `Decimal` necessitated that I had a `Number` class they both extended, as there are many situations where I would want to type-hint "anything that calculation can be done on with arbitrary precision" instead of specifically one or the other. I also provided the `NumberInterface`, `DecimalInterface`, and `FractionInterface`, though I don't think that would be necessary here as this is much more just a wrapper for BCMath than an extension of it. The main goal of my library was not to act as a wrapper for BCMath, it was to EXTEND BCMath with additional capabilities, such as trigonometric functions that have arbitrary precision, so keep that in mind when weighing input of mine that is referencing the work I have done on this topic. The design goals were different. Jordan --0000000000006240bf06152081b2 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Tue, Apr 2, 2024 at 10:24=E2=80=AF= AM Jordan LeDoux <jordan.ledo= ux@gmail.com> wrote:


On Tue, Apr 2, 2024 at 3:= 12=E2=80=AFAM Lynn <kjarli@gmail.com> wrote:

I= 9;m inexperienced when it comes to maths and the precision here, but I do h= ave some experience when it comes to what the business I work for wants. I&= #39;ve implemented BCMath in a couple of places where this kind of precisio= n is necessary, and I found that whenever I do divisions I prefer having at= least 2 extra digits. Would it make sense to internally always just store = a more accurate number? For things like additions/multiplications/subtracti= ons it could always use the highest precision, and then for divisions add l= ike=C2=A0+3~6 or something. Whenever you have numbers that have a fraction = like `10.5001` it makes sense to set it to 4, but when you have `10` it sud= denly becomes 0 when implicitly setting it.=C2=A0

For the fol= lowing examples assume each number is a BcNum:
When doing somethi= ng like `10 * 10.0000 * 10.000000000` I want the end result to have a preci= sion of at least 9 so I don't lose information. When I do `((10 / 3) * = 100) * 2` I don't want it to implicitly become 0, because the precision= here is important to me. I don't think using infinite precision here i= s a reasonable approach either. I'm not sure what the correct answer is= , perhaps it's just "always manually set the precision"?

In my library, if the scale i= s unspecified, I actually set the scale to 10 OR the length of the input st= ring, including integer decimals, whichever is larger. Since I was designin= g my own library I could do things like that as convention, and a scale of = 10 is extremely fast, even with the horrifically slow BCMath library, but c= overs most use cases (the overwhelmingly common of which is exact calculati= on of money).

My library handles scale using the f= ollowing design. It's not necessarily correct here, as I was designing = a PHP library instead of something for core, AND my library does not have t= o deal with operator overloads so I'm always working with method signat= ures instead, AND it's possible that my class/method design is inferior= to other alternatives, however it went:

1. Each n= umber constructor allowed for an optional input scale.
2. The inp= ut number was converted into the proper formatting from allowed input types= , and then the implicit scale is set to the total number of digits.
3. If the input scale was provided, the determined scale is set to that = value.
4. Otherwise, the determined scale at construction is set = to 10 or the implicit scale of "number of digits", whichever is l= arger.
5. The class contained the `roundToScale` method, which al= lowed you to provide the desired scale and the rounding method, and then wo= uld set the determined scale to that value after rounding. It contained the= `round` method with the same parameters to allow rounding to a specific sc= ale without also setting the internal determined scale at the same time.
6. The class contained the `setScale` method which set the value of= the internal determined scale value to an int without mutating the value a= t all.
7. All mathematical operation methods which depended on sc= ale, (such as div or pow), allowed an optional input scale that would be us= ed for calculation if present. If it was not present, the internal calculat= ions were done by taking the higher of the determined scale between the two= operands, and then adding 2, and then the result was done by rounding usin= g the default method of ROUND_HALF_EVEN if no rounding method was provided.=

Again, though I have spent a lot of design time o= n this issue for the math library I developed, my library did not have to d= eal with the RFC process for PHP or maintain consistency with the conventio= ns of PHP core, only with the conventions it set for itself. However, I can= provide a link to the library for reference on the issue if that would be = helpful for people that are contributing to the design aspects of this RFC.=

>=20 The current assumption is that a Number always holds a single value. How if we made it so that it held two values? They are the numerator and=20 the denominator.

Again, my experience on the = issue is with the development of my own library on the issue, however in my= case I fully separated that kind of object into its own class `Fraction`, = and gave the kinds of operations we've been discussing to the class `De= cimal`. Storing numerators and denominators for as long as possible involve= s a completely different set of math. For instance, you need an algorithm t= o determine the Greatest Common Factor and the Least Common Multiple in suc= h a class, because there are a lot of places where you would need to find t= he smallest common denominator or simplify the fraction.

Abstracting between the `Fraction` and `Decimal` so that they worked= with each other honestly introduced the most complex and inscrutable code = in my entire library, so unless fractions are themselves also a design goal= of this RFC, I would recommend against it.

Jo= rdan

An addendum:
=
Having two classes `Fraction` and `Decimal` necessitated tha= t I had a `Number` class they both extended, as there are many situations w= here I would want to type-hint "anything that calculation can be done = on with arbitrary precision" instead of specifically one or the other.= I also provided the `NumberInterface`, `DecimalInterface`, and `FractionIn= terface`, though I don't think that would be necessary here as this is = much more just a wrapper for BCMath than an extension of it. The main goal = of my library was not to act as a wrapper for BCMath, it was to EXTEND BCMa= th with additional capabilities, such as trigonometric functions that have = arbitrary precision, so keep that in mind when weighing input of mine that = is referencing the work I have done on this topic. The design goals were di= fferent.

Jordan
--0000000000006240bf06152081b2--