Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:121961 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 65600 invoked from network); 8 Dec 2023 10:14:58 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 8 Dec 2023 10:14:58 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 09F1D180051 for ; Fri, 8 Dec 2023 02:15:11 -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=-2.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DMARC_MISSING,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yw1-f182.google.com (mail-yw1-f182.google.com [209.85.128.182]) (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 ; Fri, 8 Dec 2023 02:15:10 -0800 (PST) Received: by mail-yw1-f182.google.com with SMTP id 00721157ae682-5d8e816f77eso18765087b3.0 for ; Fri, 08 Dec 2023 02:14:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=interi-co.20230601.gappssmtp.com; s=20230601; t=1702030496; x=1702635296; 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=ANz9y3avtRvKuCckSD7BcHgzBKQuxvZvP714iPeP0Bk=; b=xMtMTUJiJBoG6Zb9T1z9PbcyX/7EcWjrFcGEN6cI896SFsyKJaJjYKbZF9fmBPwMpD yEVmnw3QuaqdFsWcmKJyOjxJnBwNF2yVwgHkg1OgtoVBYuCUt5FI19v6giEFX3JLazNo NzZSmAJajxlG9TviC0xnIvwo/6xu2Z4JaF96wWhyUAK5oOBn4FcLborUAwSGhRSYeHt5 iuD0Ke/6kkrm1c7Ssw19dkQGp1husgO45UxY4QhN9t3OLG2Ua+kiZPW1xCRCvt5Ru9Jm r0KyDUZfHsNR9/uLfKZjqk/P8txz9JRXyG6L9LWoko46Duk20Wt1q3e6tL2B2xQp1ecP d8wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702030496; x=1702635296; 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=ANz9y3avtRvKuCckSD7BcHgzBKQuxvZvP714iPeP0Bk=; b=HT6ONwoxsatueiErEKmWw06ORjl6/rqaGurtFHVnPA8n9hxi4oeTs2gadvx0jJ+Zs4 WMCaYEwgqGdzPaRzDoshZy20N1Ur5RnDHv/LVmb+nAJSCX5w7BxclJnS+9MDO62nFYsZ uOv+GbjtdiqYUPGCQAPazL0mSNY1HuWqDKj1RgdzlblaBuh21uTqUH3cj5qlBV8ZZBBH e+TuJT55C+0N0e7e73FKABEEcEjtCKjLBCUhReFQ4BsWd3mkBu4xmFMXRv/tHcoWlnv4 6HkneS5GIUihEv83NPzgvpY+bbmHTIsdEaf15Tmz0tQr1/Tz8t8gP3vHpegXp2Q8JzDL iJiQ== X-Gm-Message-State: AOJu0YyrPy221stm/UpHMs32RUylhCm2sFBO0HdOCrsxByPc/95kvC46 /C9ukG5jBO8LmOLUIXT0srK8+CHh05BRHHD5u9VoJIIqPc2od4HzzbQ= X-Google-Smtp-Source: AGHT+IH6j1FwP2rw94clp01MS088WfQmgp2hpyTfJpKISzys2Z0zsrcDb76DBWZCqRCyHkqZyndr+0vD/rnZeGJUB4E= X-Received: by 2002:a81:ad14:0:b0:5d7:1940:b36a with SMTP id l20-20020a81ad14000000b005d71940b36amr3827262ywh.54.1702030495852; Fri, 08 Dec 2023 02:14:55 -0800 (PST) MIME-Version: 1.0 References: <18c42fdbb30.2831.17a3710df6d58f02ca570cc47e197a63@interi.co> In-Reply-To: Date: Fri, 8 Dec 2023 19:14:44 +0900 Message-ID: To: "G. P. B." Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000001a446c060bfcdbcb" Subject: Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type From: alex.pravdin@interi.co (Alexander Pravdin) --0000000000001a446c060bfcdbcb Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 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 easily casted to boolean false. This is also why I think we need a scalar decimal type. > >> It works the same as "float" in terms of its usage and type casting >> except >> 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 types 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 conversions > 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? > 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 decimals= , > 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 the internals community prefers. > New declare directive "default_decimal" is added. When used, literals an= d > >> math operations return decimal by default instead of float. This is to >> 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 intention is to be able to write clean all-decimal units of code and not break the backward compatibility. The old code should work as it was before. At the 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 complex language structures and excessive typehints or explicit conversions. The 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? > New language construct "as_decimal()" is added to produce decimal math >> results for literals and math operations instead of float without >> intermediary float: >> >> $var =3D 5 / 2; // returns float 2.5 >> $var =3D as_decimal(5 / 2); // returns decimal 2.5 >> >> This is a kind of "default_decimal" for a specific operation. >> > > Again, this should return a decimal instead IMHO. > While it will work from the logical perspective, additional conversions from decimal to float may incur performance issues in the existing code that relies on floats only. Again, my intention here is to not break backward compatibility and not introduce performance issues to the existing code. > > >> If mixed float and decimal operands are used in a math operation, decima= l >> is converted to float by default. If "default_decimal" directive or >> "as_decimal()" construct is used, float is converted to decimal (with a >> warning): >> >> $f =3D (float) 0.2; >> $d =3D (decimal) 0.2; >> >> $r =3D $f + $d; // returns float result by default >> $r =3D as_decimal($f + $d); // returns decimal result with a warning abo= ut >> implicit float to decimal conversion >> >> All builtin functions that currently accept float also accept decimal. S= o >> users don't need to care about separate function sets, and PHP developer= s >> don't need to maintain separate sets of functions. If such functions get >> the decimal parameter, they return decimal. If they have more than one >> float parameter and mixed float and decimal passed, decimals converted t= o >> float by default. If "default_decimal" or "as_decimal" used, float is >> converted to decimal with the warning. >> > > Messing with the return value type has already proved controversial. > And as I said previously, I am dead against having implicit float to > decimal conversions. > Making the functions type generic is something that I am fine, however. > I'm fine with generic functions as well. I'm most probably not aware of all the ongoing discussions. If the internals community prefers generic functions, I'm absolutely fine with it. > > >> 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 decimal > 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 splittin= g > the bits into a 32-bit unsigned integer for the numerator and an 32-bit > signed integer for the denominator should provide us with enough reasonab= le > 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 some 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, but also to make all the alternatives useless, cover their functionality by builtin tools, to free users from thinking about workarounds and bandaids. 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. > > >> All of the points above are subject to discussions, it is not an RFC >> candidate right now. So please share your opinions. >> >> I know that the implementation of this will require a lot of work. But I >> don't think this is a stopper from formulating the requirements. >> Sometimes, >> any project requires big changes to move forward. I'm pretty sure this >> functionality will move PHP to the next level and expand its area of >> applications. My thoughts here are mostly from the user's perspective, >> I'm >> not so familiar with PHP internal implementation. But I think this >> feature >> can be a good goal for PHP 9. >> > > Yes, this is a major project, and as said above I have also thought about > adding a rational number type. > But the main hurdle for this is changing the zval structure and applying > the change everywhere to the engine and extensions. > I understand that changing something that is at the core of the whole project is a huge butthurt. But let's focus on end benefits :) I love PHP but it is also well-known that it is perceived as a language NOT for "serious and mature" projects. Partly because if you try working with financial data for a bank app, for example, you immediately have troubles choosing a workaround to work with fractional numbers and the code you write will look weird. 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 want to change and make PHP powerful enough for this kind of applications. Best regards, Alex. --0000000000001a446c060bfcdbcb--