Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:121989 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 32971 invoked from network); 12 Dec 2023 13:04:05 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 12 Dec 2023 13:04:05 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 14927180052 for ; Tue, 12 Dec 2023 05:04:20 -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.1 required=5.0 tests=BAYES_00,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 autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pg1-f182.google.com (mail-pg1-f182.google.com [209.85.215.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 ; Tue, 12 Dec 2023 05:04:19 -0800 (PST) Received: by mail-pg1-f182.google.com with SMTP id 41be03b00d2f7-5c67c1ad5beso4960584a12.1 for ; Tue, 12 Dec 2023 05:04:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702386242; x=1702991042; 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=h2C+fwU1912Me0iMjGrqnNMoHjGNzj6wKKZCiCyYHQM=; b=S/RldNclyczAv5kKIq59NVDPmyUQLLv58XiRcCgPR3OSIjlZYppLM9hWatiLlWrRXq xp0vexvXlipgBagzJ4O0AdG1lHwoxGBegAfiBKyLIHrgMzy1908S0MkKRqUeDP5KM1VQ MlW8vTXLddftedq4yI+h1XZw+qd2EkB++zp/LY+lMO5fxlnE2Cx/YAcwymDFsdw4fMus FkOJBbab1pYHQyvcc/S0CMCyORZOZ72CocX490rQMrkwnTa4I9TO8Z2TmX9voy68Ae2q fRuXE2S91AFrwbsYTrf9FxbSipaVNIwHJlEShUX6P5S3bHx9J7eFPFQSmVB+Nb+TlqBF SiMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702386242; x=1702991042; 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=h2C+fwU1912Me0iMjGrqnNMoHjGNzj6wKKZCiCyYHQM=; b=FcaHZmkFxpWNkRbEco4Lz9sRzBxQBOlYRiHMt6wZoayNR8tjNygahEUWNaFcXw7oIU sFP3f48k8LI1Bcmsw+s27NFnmflKA30FvYIzAjKQgGIPUT5neTVA8gw9Y+oqiemxZPOY 5Rk9EFZq65p2QAeYJrrxt3rN9JdI9bRQkLDcm0RRpCHb76VoMh3V9yVCNFWGPSMCsoLc ueJffACTMYcz/d40s7SVdxU3Qf4aOFvSDwRdvkpyW6adirp8C4UPp1k+AQLBAHnLqeE0 a5jHI6ixVYJhqTbck2GQA4P7luEYCCSlFE06RXdTidmw8ju1hf3U/fvktEU9B+10UJQs 0uoQ== X-Gm-Message-State: AOJu0YwmnwRtWh/OdiqLn1UoQIqjdy6qwAqc+Jy4jRavADPDehJypYGT P+EdpX62OZHD0Grta/QEQE8HNLUqWoaEQonuyf9B2+lMurQ= X-Google-Smtp-Source: AGHT+IHKuYK8gAjeLE4hDp7KQPvosPoxBGfHjtjHUB0Sj5cNAJNGJ7QB00L4EzemPg7XEmwqitOaoIN6gBQ0QQjjX0M= X-Received: by 2002:a17:90a:68cf:b0:277:68c3:64b9 with SMTP id q15-20020a17090a68cf00b0027768c364b9mr9529766pjj.5.1702386242003; Tue, 12 Dec 2023 05:04:02 -0800 (PST) MIME-Version: 1.0 References: <18c42fdbb30.2831.17a3710df6d58f02ca570cc47e197a63@interi.co> In-Reply-To: Date: Tue, 12 Dec 2023 13:03:50 +0000 Message-ID: To: Alexander Pravdin Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000039a8a0060c4faf4e" Subject: Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type From: george.banyard@gmail.com ("G. P. B.") --00000000000039a8a0060c4faf4e Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 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 easily > casted to boolean false. This is also why I think we need a scalar decima= l > 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 excep= t >>> 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 type= s > 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 an= y > 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 are 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 i= s > not a key point of my proposal. If the community prefers errors instead o= f > 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 decimal= s, >> 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 a= nd >> >>> 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 wh= y > I proposed this directive. Can you suggest something better to achieve th= e > 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, whereas 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 decima= l >> 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 and = an >> 32-bit signed integer for the denominator should provide us with enough >> 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 ar= e >> 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 som= e > intermediary values while performing complex calculations. I could be > wrong, but fractional numbers limited to 64 bits sound like a bandaid. Th= e > 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. > 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 such 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 who 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 want > 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 using 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 effectively 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 --00000000000039a8a0060c4faf4e--