Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:121991 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 57627 invoked from network); 12 Dec 2023 21:00:22 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 12 Dec 2023 21:00:22 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 169D0180069 for ; Tue, 12 Dec 2023 13:00:38 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-oi1-f181.google.com (mail-oi1-f181.google.com [209.85.167.181]) (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, 12 Dec 2023 13:00:37 -0800 (PST) Received: by mail-oi1-f181.google.com with SMTP id 5614622812f47-3b9b6ba42a4so2841814b6e.0 for ; Tue, 12 Dec 2023 13:00:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702414820; x=1703019620; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=2efGI1jXSAjUuCxC1lQv1k0w2dtHF+jTW+A3+STIUl8=; b=MW1xXlwcJMUy2KraAMEQt5qGctdiu6DsYGG3Ya2T4LxgTdtQXrQNsIdXwvfX3KssS/ BwUhiJ8KtoCzrpDBT/y745Lxm2ob9ReK52DuQXwHYSPxEa4lN4umLzb5MwB+S5tcH20h GmwWmEjCJNOUfI0PJ0lL4wD88jpLR8eeUmCzRNJMy7trR1K24B68g72mnehDC3gN4PV3 FSC2OlgHlcbxlULZow6xTqOGVtz9NS+ypNPz6AstsejaC4I1AGMjexZFfp9jCHA+7vx3 3IErzSRCDOrCPBcMGdym/JZBAP92KSNqMVQH2JhSSKJhqKK6eZl2Nlvks8CmuQvw8HV/ KBzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702414820; x=1703019620; h=content-transfer-encoding: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=2efGI1jXSAjUuCxC1lQv1k0w2dtHF+jTW+A3+STIUl8=; b=uEgGrD0PWvA+rA3M8Gf+0dbyRTv4h0y3Vbs2Ovm1EM6dlaITa/bzffg/lakEynBTqV tBTcm0KHch08g31/nNed2BZqu/dCecT2yaIn9H9pG271NBNMmwWjvkXWOO9XIhc4db4B tWmsvWIuz3EbCIYLOFljd+CL5NhFfLwGhjXNYWGkoNujXalYeVZwnexYQrdIATGVWu2K g5A2HXtaagFxvPpQu2hwmT3cXon7T7gP2WIv4ENlYGuruOf5MfKZaFI6yIRYViMSuQSH mczTeDH2idcG+aEokGjKqqfg+wI2Kpetearm0FHpEWrCfwv6rsU4teHpgttPTQsMNvgI xgWQ== X-Gm-Message-State: AOJu0YwY/Uef4ybyDlJZ9RAMvMYJ3p/IYATIfT0ab4VzYU828EawJKfF AJ+PBCPHJbKos0X7wD/Dp7uFM3MZSuWsEYv5JTJ7PrQEKMZEFw== X-Google-Smtp-Source: AGHT+IFb8LM3Wd5PaDbAt9H8gAqZHrpIdufSWIxR7sf+W3gtdGXswEDhYFRBVDyDRA1WchxvkPHeQCozuCSaykvydkI= X-Received: by 2002:a05:6808:34b:b0:3b8:5b72:fc71 with SMTP id j11-20020a056808034b00b003b85b72fc71mr3213688oie.20.1702414820110; Tue, 12 Dec 2023 13:00:20 -0800 (PST) MIME-Version: 1.0 References: <18c42fdbb30.2831.17a3710df6d58f02ca570cc47e197a63@interi.co> In-Reply-To: Date: Tue, 12 Dec 2023 21:59:57 +0100 Message-ID: To: "G. P. B." Cc: Alexander Pravdin , internals@lists.php.net Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type From: landers.robert@gmail.com (Robert Landers) On Tue, Dec 12, 2023 at 2:04=E2=80=AFPM G. P. B. = wrote: > > On Fri, 8 Dec 2023 at 10:14, Alexander Pravdin > wrote: > > > On Thu, Dec 7, 2023 at 11:36=E2=80=AFPM G. P. B. wrote: > > > > - Objects are always casted to true, GMP(0) will equal to true. > >>> > >> > >> This is incorrect, GMP object do _not_ support casts to bool > >> See https://3v4l.org/LHpD1 > >> > > > > This is weird. Any PHP user would expect that a zero number can be easi= ly > > casted to boolean false. This is also why I think we need a scalar deci= mal > > type. > > > > Internal objects can overload casts, SimpleXML overloads the boolean cast > already. > We could add this to GMP to return false for 0. > > > > It works the same as "float" in terms of its usage and type casting exc= ept > >>> for one thing. Float value can be passed to a decimal argument or > >>> typecasted with a warning like "Float to decimal conversion may incur > >>> unexpected results". > >>> > >>> Decimal to float conversion is allowed and smooth: > >>> > >>> function f (float $value) {} > >>> > >>> f(0.2); > >>> > >>> f(0.2d); // allowed with no warnings > >>> > >> > >> I disagree with this part, floats can not represent decimal values > >> properly e.g. > >> $f1 =3D 0.1; > >> $f2 =3D 0.2; > >> $f3 =3D 0.3; > >> var_dump($f1 + $f2 =3D=3D=3D $f3); > >> > > will return false. > >> As such, floats are not at all compatible with decimals. > >> > > > > Yes, I know that. I mentioned that we can not convert float to decimal > > without an intermediate value where we apply rounding and get a > > human-readable value in some representation (string or whatsoever). > > > > My intention was to provide implicit conversion with warnings because I > > guess that the majority of end users will expect that numeric scalar ty= pes > > are interoperable. To not make them scared and point them to issues in > > their code instead of slapping their hands immediately when they run > > something that is not so correct. > > > > > > > >> Moreover, the whole point of adding a warning when implicit conversion= s > >> from int to float happen was to be able to warn before elevating the > >> warning to a TypeError. > >> > > > > Sorry, I'm not aware of issues of converting ints to floats. Are there = any > > issues? I understand the issue of the backward conversion, but not the > > forward one. Could you add details here? > > > > I meant converting floats to int. > But you can lose precision when converting an integer to float as there a= re > only 53 bits for the coefficient. > > > > Therefore, introducing behaviour that warns instead of throwing a > >> TypeError is already a no-go from my PoV. > >> > > > > I'm okay with TypeErrors for float to decimal conversions as well. This= is > > not a key point of my proposal. If the community prefers errors instead= of > > warnings - that's also fine. > > > > > > Literal numbers in the code are converted to floats by default. If > >>> prepended by the "(decimal)" typecast, the decimal result is produced > >>> without an intermediary float. > >>> > >> > >> This behaviour is rather suboptimal, I'd rather have literals be decim= als, > >> as decimals to floats should always be a reasonable implicit coercion > >> considering we already do int to float. > >> > > > > Is it optimal to perform conversions on every fractional literal? This = is > > also not a key point for me and I'm okay with any implementation that t= he > > internals community prefers. > > > > > > > >> New declare directive "default_decimal" is added. When used, literals= and > >> > >>> math operations return decimal by default instead of float. This is t= o > >>> simplify creating source files working with decimals only. > >>> > >> > >> Please no, no new declare directives that affect engine behaviour. > >> Strict types was already a mistake because of this IMHO. > >> > > > > I didn't know that the strict types directive was a mistake. My intenti= on > > is to be able to write clean all-decimal units of code and not break th= e > > backward compatibility. The old code should work as it was before. At t= he > > same time, there are use cases when the whole class/project should be > > written with decimals only. As a user, I want to do that without comple= x > > language structures and excessive typehints or explicit conversions. Th= e > > all-decimal code should be as clean as it is now with floats. This is = why > > I proposed this directive. Can you suggest something better to achieve = the > > same? > > > > The issue is that I don't think having arbitrary precision decimals as a > core language feature is a necessity compared to rational types. > A cast from rational to float wouldn't produce a large round trip, wherea= s > trying to figure out arbitrary precision is more difficult. > But in any case, having a declare/INI or whatever that changes the > behaviour of the engine/language is not a good design choice. > > > > [...] > > > > The new type uses libmpdec internally to perform decimal calculations > >> (same > >> > >>> as Python). > >>> > >> > >> I really don't think we need arbitrary precision decimals. > >> > > I'm also not convinced using a floating point spec is the most sensible= , > >> due to the rounding errors this is going to introduce. > >> The non-arbitrary IEEE 754-2008 specification cannot describe the deci= mal > >> 123457.1467 exactly, which is frankly pointless. > >> > >> Decimals, or more broadly rational numbers that, outside numerical > >> computations, that are going to be used are not going to need huge > >> denominators. > >> > >> I've been thinking about this for a while, and I personally think that > >> rational numbers are just better than trying to support only decimals. > >> And considering we have 64 bits to play with for a new zval type > >> splitting the bits into a 32-bit unsigned integer for the numerator an= d an > >> 32-bit signed integer for the denominator should provide us with enoug= h > >> reasonable rational numbers. > >> As any number that do not fit in this structure seems to be something > >> relegated to the world of numerical computation where floats are what = are > >> mostly used anyway. > >> > > > > If you can suggest a better way of working with fractional numbers - > > please do :) But IMO limiting the language by 64 bits is not a good way= . It > > is more easy to go over the limit than you may think :) Especially in s= ome > > intermediary values while performing complex calculations. I could be > > wrong, but fractional numbers limited to 64 bits sound like a bandaid. = The > > language will tell users "hey, you can do something general, but if you > > want something else please don't use me at all or involve bandaids with > > extensions". My key point is not only to allow working with decimals, b= ut > > also to make all the alternatives useless, cover their functionality by > > builtin tools, to free users from thinking about workarounds and bandai= ds. > > From my POV, introducing a new decimal type that does not cover the > > GMP/bcmath/ext-decimal functionality is pointless and a waste of time. > > > > Again, the use cases for arbitrary precision numbers seems rather limited= , > and having this as an extension does not seem problematic at all. > My current issue is that there is no way to represent "small" numbers suc= h > as 0.1 or 5.8 exactly. > Arbitrary precision is a totally different ballpark, be that for integers > and/or fractional values and makes everything slow, just look at Python w= ho > is *finally* investing time and money to make the most common numbers > (those that fit in a machine word) not be abysmally slow. > > > > [...] > > > > > > > How quickly you would be able to read something like this: > > gmp_add(gmp_mul(gmp_div(gmp_sub($value, $add), $value2, $factor, > > gmp_sin($value3), gmp_intval($value))) ? > > > This absence of intuitive readability makes the development and support > > difficult and it's better to choose another language. This is what I wa= nt > > to change and make PHP powerful enough for this kind of applications. > > > > GMP supports operator overloading, so you do not need to write this, and = as > far as I see, ext/decimal *also* supports operator overloading so you can > just write it using the normal arithmetic operations. > Moreover, it supports type casts so you can just do (int) $GMP instead of > gmp_intval($GMP); > And it also supports using the comparisons operatos on it instead of usin= g > gmp_cmp() > > The only thing that is, currently, not possible to do is a cast _to_ GMP > using (GMP), but maybe that's something that could be added to the engine > for internal objects, but I'm not sure about this. > > It seems, your main motivation to have this as a language feature is to > have access to operator overloading and casting behaviour, that internal > objects already support. > Which diminish the cost/benefit of making the engine changes, especially = if > the default behaviour doesn't change and one needs to maintain effectivel= y > two different versions of PHP depending on if it is in "decimal" or > "floating" mode, which raises a plethora of questions just in its own. > > Best regards, > > Gina P. Banyard Hey Gina, > GMP supports operator overloading GMP kinda-sorta-most-of-the-time supports operator overloading. Sometimes ... it doesn't. I implemented a field library in PHP (for work a couple of years ago) and occasionally, overloading would cast things back to float/int and break the math. I don't have access to that code, so I don't have any examples readily available (and the fact that an extension can do overloading but we can't in user-land is a whole different can of worms which made this library ridiculously hard to work with -- we rewrote everything in Scala and never looked back). Needless to say, if I were to go into a project that required GMP, I wouldn't trust the overloading. Just my 2=C2=A2 Robert Landers Software Engineer Utrecht NL