Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:121938 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 29379 invoked from network); 7 Dec 2023 06:36:20 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 7 Dec 2023 06:36:20 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D4B7A180031 for ; Wed, 6 Dec 2023 22:36:30 -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-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) (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 ; Wed, 6 Dec 2023 22:36:30 -0800 (PST) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-1d0aaa979f0so4127225ad.0 for ; Wed, 06 Dec 2023 22:36:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=interi-co.20230601.gappssmtp.com; s=20230601; t=1701930976; x=1702535776; darn=lists.php.net; h=mime-version:subject:user-agent:message-id:date:to:from:from:to:cc :subject:date:message-id:reply-to; bh=/8ifqrdhh7QW2/xFoMUzIYbTLi66gQwG0tqOsIRNeu0=; b=LtaX6J7QtDPfsy/1WVo+1EaPbPmU1qfk9SfTalcWKVIJy92C5gPe5EsIdZtmvffVoj JCh5Jylvw5zMBsExpmj1DHdzYcvx5iEr4EL1Xd9G8fvi9ymbTJHW6iDSpFDvNP3x1PwW tWWdvv1XHxvIc98r+CcZftV89g8Y0ehQtV2Q9iPATIuoGIihwfETuJA4uzEsXEqot5mF 8M2sUZiQ/pf43erZqdFbSFE5KekaqYDBOYDO/BcWa/CItdOVaxghN0iDcgS3ZIVBGrAy rb4i66fZAxZ3I1W86X+1d6HFULfqBcM89LoR2fbZ/q9ReGSZjLM7SXsZ1J9zxr3MTk2J h6Sg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701930976; x=1702535776; h=mime-version:subject:user-agent:message-id:date:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/8ifqrdhh7QW2/xFoMUzIYbTLi66gQwG0tqOsIRNeu0=; b=pQm5Zp/84qzuGoGcnBC+i+Ra8ikyfu6bQ7SaKJFsxxrK6XpnFJ4LCOSbVNdRC+1q89 PlhufnDknJIA7lNzFbzvVgxWazRPZ+KPkdh1VWgGP0hLKlAYoCQDlPAD8HOFdkBmYRHO UvqZSDo3/750s2aQK5YkHDXrSqcQiuLEvdYrkwgUCKFeo9b6+OnfJUFa3DWumGi5pYY3 2ybGygW32gsTXUCS6OUTnttglkmMjYZT4dz9qnxu1y8LIVH+L+R5HO6C2w/SSmS+KjEQ dlNScqvEgA/d8iGxCO5kWMvLOmen3FbfDIop4LVVl1lyQJ39clafpyicJeq4zWIJOIcF 0GeQ== X-Gm-Message-State: AOJu0YzJtVENpbjouTElVI1tbLYPedcwHVKulD7uB1fsxIfdzghSgCHu IStrexUInsjAL07iF7YqNFmwocAICsWlsOwoWdg= X-Google-Smtp-Source: AGHT+IF6OPEHBGxOQlql4cuR0pYXIn8lmg19DWh+u+0kMNHX6C/wXNGR8mq3PhwK1AfJPiQlUzw3Uw== X-Received: by 2002:a17:902:dac4:b0:1d0:8abd:4e30 with SMTP id q4-20020a170902dac400b001d08abd4e30mr1931252plx.87.1701930975775; Wed, 06 Dec 2023 22:36:15 -0800 (PST) Received: from [153.147.201.240] (p266240-omed01.tokyo.ocn.ne.jp. [153.147.201.240]) by smtp.gmail.com with ESMTPSA id n15-20020a170902e54f00b001d087610dbbsm536706plf.55.2023.12.06.22.36.14 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Dec 2023 22:36:15 -0800 (PST) To: Date: Thu, 07 Dec 2023 15:36:14 +0900 Message-ID: <18c42fdbb30.2831.17a3710df6d58f02ca570cc47e197a63@interi.co> User-Agent: AquaMail/1.48.1 (build: 104801389) MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="18c42fdbd9fd752831452b8a8" Subject: Proposal: Arbitrary precision native scalar type From: alex.pravdin@interi.co (Alex Pravdin) --18c42fdbd9fd752831452b8a8 Content-Type: text/plain; format=flowed; charset="us-ascii" Content-Transfer-Encoding: 8bit Hello internals, This is the second round of the discussion regarding arbitrary precision scalar type integration into PHP. The previous part: https://marc.info/?l=php-internals&m=168250492216838&w=2 was initiated by me before deep diving into the work with decimals in PHP. After 6 months of working, I would like to update my proposal taking into account my experience and the previous discussion. Today's alternatives and their problems are the following. bcmath: - Workaround: using string type. - Unintuitive function calls instead of regular math operations. - Unintuitive strings instead of numbers. People want to work with numbers. - Can not use proper type-hinting. - Can use PHP's basic type coercions. Ext-decimal: - Third-party extension. - Workaround: implements the Decimal class that allows basic regular math operations. - Requires using class methods for the rest of math operations. - The latest release was in 2019 and there's a danger that it will be unmaintained and not compatible with the future PHP releases. - The php-decimal documentation website is currently down. - Since objects are always casted to true when not null, "(bool) Decimal(0)" will equal to true which is not intuitive. - IDEs are often confused when you use math operations on objects while the code works fine. GMP: - Workaround: implements the GMP class that allows basic math operations. - Requires using separate functions for the rest of operations. - Objects are always casted to true, GMP(0) will equal to true. Accounting for all of the above, I suggest adding a native numeric scalar arbitrary precision type called "decimal". Below are the preliminary requirements for implementation. Decimal values can be created from literals by specifying a modifier or using the (decimal) typecast: $v = 0.2d; $v = (decimal) 0.2; // Creates a decimal value without intermediary float It uses the precision and scale defined in php.ini. The "decimal" typehint allows to define custom precision and scale: decimal(20,5). It accepts regular expressions returning ints in the execution context. It accepts int constants and literals in class field and function argument definitions. New functions added: get_scale and get_precision to return corresponding values about a decimal value. If decimal value with different scale and precision is going to be assigned to a variable or parameter with smaller scale or precision, it first tries to convert the value. If it's not possible, then an exception is thrown like "Can not convert decimal (a, b) xxxxx.yyyy to decimal(c, d)". If possible, it performs the conversion and generates a warning like "Assigning decimal(a, b) to decimal(c, d) may be not possible with some values". 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 Function "str_to_decimal" added to convert string representation of numbers to decimals. Typecast from string to decimal works the same as the "str_to_decimal" function. Function "float_to_decimal" added to explicitly convert floats to decimals. It performs float to string conversions using php.ini settings as defaults but also accepts parameters to configure the conversion. Then, it converts string to decimal. Since the main problem of float to decimal conversion is that we don't know the exact result until we use some rounding when transforming it to a human-readable format, it looks like the step of the conversion to a string is inevitable. Any more optimized algorithms are welcome. Explicit typecast from float to decimal works the same as "float_to_decimal" function with all default values but also throws a warning. This is to encourage users to use explicit conversion with the "float_to_decimal" function and control the results. 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. New declare directive "default_decimal" is added. When used, literals and math operations return decimal by default instead of float. This is to simplify creating source files working with decimals only. New language construct "as_decimal()" is added to produce decimal math results for literals and math operations instead of float without intermediary float: $var = 5 / 2; // returns float 2.5 $var = as_decimal(5 / 2); // returns decimal 2.5 This is a kind of "default_decimal" for a specific operation. If mixed float and decimal operands are used in a math operation, decimal 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 = (float) 0.2; $d = (decimal) 0.2; $r = $f + $d; // returns float result by default $r = as_decimal($f + $d); // returns decimal result with a warning about implicit float to decimal conversion All builtin functions that currently accept float also accept decimal. So users don't need to care about separate function sets, and PHP developers 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 to float by default. If "default_decimal" or "as_decimal" used, float is converted to decimal with the warning. The new type uses libmpdec internally to perform decimal calculations (same as Python). 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. -- Best regards, Alex Pravdin --18c42fdbd9fd752831452b8a8--