Add new Bitwise Functions introduced in MS Excel 2013 (#603)
* - Added calculation engine support for the new bitwise functions that were added in MS Excel 2013 - BITAND() Returns a Bitwise 'And' of two numbers - BITOR() Returns a Bitwise 'Or' of two number - BITXOR() Returns a Bitwise 'Exclusive Or' of two numbers - BITLSHIFT() Returns a number shifted left by a specified number of bits - BITRSHIFT() Returns a number shifted right by a specified number of bits
This commit is contained in:
parent
9b44cf3418
commit
67cdee6033
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -12,8 +12,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
- Add excel function EXACT(value1, value2) support - [595](https://github.com/PHPOffice/PhpSpreadsheet/pull/595)
|
- Add excel function EXACT(value1, value2) support - [595](https://github.com/PHPOffice/PhpSpreadsheet/pull/595)
|
||||||
- Support workbook view attributes for Xlsx format - [#523](https://github.com/PHPOffice/PhpSpreadsheet/issues/523)
|
- Support workbook view attributes for Xlsx format - [#523](https://github.com/PHPOffice/PhpSpreadsheet/issues/523)
|
||||||
- Read and write hyperlink for drawing image - [#490](https://github.com/PHPOffice/PhpSpreadsheet/pull/490)
|
- Read and write hyperlink for drawing image - [#490](https://github.com/PHPOffice/PhpSpreadsheet/pull/490)
|
||||||
- Fix ISFORMULA() function to work with a cell reference to another worksheet
|
- Added calculation engine support for the new bitwise functions that were added in MS Excel 2013
|
||||||
- Added calculation engine support for the new functions that were added in MS Excel 2013 and MS Excel 2016
|
- BITAND() Returns a Bitwise 'And' of two numbers
|
||||||
|
- BITOR() Returns a Bitwise 'Or' of two number
|
||||||
|
- BITXOR() Returns a Bitwise 'Exclusive Or' of two numbers
|
||||||
|
- BITLSHIFT() Returns a number shifted left by a specified number of bits
|
||||||
|
- BITRSHIFT() Returns a number shifted right by a specified number of bits
|
||||||
|
- Added calculation engine support for other new functions that were added in MS Excel 2013 and MS Excel 2016
|
||||||
- Text Functions
|
- Text Functions
|
||||||
- CONCAT() Synonym for CONCATENATE()
|
- CONCAT() Synonym for CONCATENATE()
|
||||||
- NUMBERVALUE() Converts text to a number, in a locale-independent way
|
- NUMBERVALUE() Converts text to a number, in a locale-independent way
|
||||||
|
@ -44,6 +49,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fix ISFORMULA() function to work with a cell reference to another worksheet
|
||||||
- Xlsx reader crashed when reading a file with workbook protection - [#553](https://github.com/PHPOffice/PhpSpreadsheet/pull/553)
|
- Xlsx reader crashed when reading a file with workbook protection - [#553](https://github.com/PHPOffice/PhpSpreadsheet/pull/553)
|
||||||
- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)
|
- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)
|
||||||
- Could not open CSV file containing HTML fragment - [#564](https://github.com/PHPOffice/PhpSpreadsheet/issues/564)
|
- Could not open CSV file containing HTML fragment - [#564](https://github.com/PHPOffice/PhpSpreadsheet/issues/564)
|
||||||
|
|
|
@ -369,6 +369,31 @@ class Calculation
|
||||||
'functionCall' => [Statistical::class, 'BINOMDIST'],
|
'functionCall' => [Statistical::class, 'BINOMDIST'],
|
||||||
'argumentCount' => '4',
|
'argumentCount' => '4',
|
||||||
],
|
],
|
||||||
|
'BITAND' => [
|
||||||
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
|
'functionCall' => [Engineering::class, 'BITAND'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
|
'BITOR' => [
|
||||||
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
|
'functionCall' => [Engineering::class, 'BITOR'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
|
'BITXOR' => [
|
||||||
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
|
'functionCall' => [Engineering::class, 'BITOR'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
|
'BITLSHIFT' => [
|
||||||
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
|
'functionCall' => [Engineering::class, 'BITLSHIFT'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
|
'BITRSHIFT' => [
|
||||||
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
|
'functionCall' => [Engineering::class, 'BITRSHIFT'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
'CEILING' => [
|
'CEILING' => [
|
||||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
'functionCall' => [MathTrig::class, 'CEILING'],
|
'functionCall' => [MathTrig::class, 'CEILING'],
|
||||||
|
|
|
@ -2423,6 +2423,179 @@ class Engineering
|
||||||
return self::$twoSqrtPi * $sum;
|
return self::$twoSqrtPi * $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate arguments passed to the bitwise functions.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static function validateBitwiseArgument($value)
|
||||||
|
{
|
||||||
|
$value = Functions::flattenSingleValue($value);
|
||||||
|
|
||||||
|
if (is_int($value)) {
|
||||||
|
return $value;
|
||||||
|
} elseif (is_numeric($value)) {
|
||||||
|
if ($value == (int) ($value)) {
|
||||||
|
$value = (int) ($value);
|
||||||
|
if (($value > pow(2, 48) - 1) || ($value < 0)) {
|
||||||
|
throw new Exception(Functions::NAN());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception(Functions::NAN());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITAND.
|
||||||
|
*
|
||||||
|
* Returns the bitwise AND of two integer values.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BITAND(number1, number2)
|
||||||
|
*
|
||||||
|
* @category Engineering Functions
|
||||||
|
*
|
||||||
|
* @param int $number1
|
||||||
|
* @param int $number2
|
||||||
|
*
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function BITAND($number1, $number2)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$number1 = self::validateBitwiseArgument($number1);
|
||||||
|
$number2 = self::validateBitwiseArgument($number2);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number1 & $number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITOR.
|
||||||
|
*
|
||||||
|
* Returns the bitwise OR of two integer values.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BITOR(number1, number2)
|
||||||
|
*
|
||||||
|
* @category Engineering Functions
|
||||||
|
*
|
||||||
|
* @param int $number1
|
||||||
|
* @param int $number2
|
||||||
|
*
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function BITOR($number1, $number2)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$number1 = self::validateBitwiseArgument($number1);
|
||||||
|
$number2 = self::validateBitwiseArgument($number2);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number1 | $number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITXOR.
|
||||||
|
*
|
||||||
|
* Returns the bitwise XOR of two integer values.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BITXOR(number1, number2)
|
||||||
|
*
|
||||||
|
* @category Engineering Functions
|
||||||
|
*
|
||||||
|
* @param int $number1
|
||||||
|
* @param int $number2
|
||||||
|
*
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function BITXOR($number1, $number2)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$number1 = self::validateBitwiseArgument($number1);
|
||||||
|
$number2 = self::validateBitwiseArgument($number2);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number1 ^ $number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITLSHIFT.
|
||||||
|
*
|
||||||
|
* Returns the number value shifted left by shift_amount bits.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BITLSHIFT(number, shift_amount)
|
||||||
|
*
|
||||||
|
* @category Engineering Functions
|
||||||
|
*
|
||||||
|
* @param int $number
|
||||||
|
* @param int $shiftAmount
|
||||||
|
*
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function BITLSHIFT($number, $shiftAmount)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$number = self::validateBitwiseArgument($number);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$shiftAmount = Functions::flattenSingleValue($shiftAmount);
|
||||||
|
|
||||||
|
$result = $number << $shiftAmount;
|
||||||
|
if ($result > pow(2, 48) - 1) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BITRSHIFT.
|
||||||
|
*
|
||||||
|
* Returns the number value shifted right by shift_amount bits.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BITRSHIFT(number, shift_amount)
|
||||||
|
*
|
||||||
|
* @category Engineering Functions
|
||||||
|
*
|
||||||
|
* @param int $number
|
||||||
|
* @param int $shiftAmount
|
||||||
|
*
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public static function BITRSHIFT($number, $shiftAmount)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$number = self::validateBitwiseArgument($number);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$shiftAmount = Functions::flattenSingleValue($shiftAmount);
|
||||||
|
|
||||||
|
return $number >> $shiftAmount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ERF.
|
* ERF.
|
||||||
*
|
*
|
||||||
|
|
|
@ -32,6 +32,11 @@ BIN2DEC
|
||||||
BIN2HEX
|
BIN2HEX
|
||||||
BIN2OCT
|
BIN2OCT
|
||||||
BINOMDIST
|
BINOMDIST
|
||||||
|
BITAND
|
||||||
|
BITLSHIFT
|
||||||
|
BITOR
|
||||||
|
BITRSHIFT
|
||||||
|
BITXOR
|
||||||
CEILING
|
CEILING
|
||||||
CELL
|
CELL
|
||||||
CHAR
|
CHAR
|
||||||
|
|
|
@ -623,6 +623,91 @@ class EngineeringTest extends TestCase
|
||||||
return require 'data/Calculation/Engineering/OCT2HEX.php';
|
return require 'data/Calculation/Engineering/OCT2HEX.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBITAND
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
public function testBITAND($expectedResult, array $args)
|
||||||
|
{
|
||||||
|
$result = Engineering::BITAND(...$args);
|
||||||
|
self::assertEquals($expectedResult, $result, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBITAND()
|
||||||
|
{
|
||||||
|
return require 'data/Calculation/Engineering/BITAND.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBITOR
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
public function testBITOR($expectedResult, array $args)
|
||||||
|
{
|
||||||
|
$result = Engineering::BITOR(...$args);
|
||||||
|
self::assertEquals($expectedResult, $result, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBITOR()
|
||||||
|
{
|
||||||
|
return require 'data/Calculation/Engineering/BITOR.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBITXOR
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
public function testBITXOR($expectedResult, array $args)
|
||||||
|
{
|
||||||
|
$result = Engineering::BITXOR(...$args);
|
||||||
|
self::assertEquals($expectedResult, $result, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBITXOR()
|
||||||
|
{
|
||||||
|
return require 'data/Calculation/Engineering/BITXOR.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBITLSHIFT
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
public function testBITLSHIFT($expectedResult, array $args)
|
||||||
|
{
|
||||||
|
$result = Engineering::BITLSHIFT(...$args);
|
||||||
|
self::assertEquals($expectedResult, $result, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBITLSHIFT()
|
||||||
|
{
|
||||||
|
return require 'data/Calculation/Engineering/BITLSHIFT.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBITRSHIFT
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed[] $args
|
||||||
|
*/
|
||||||
|
public function testBITRSHIFT($expectedResult, array $args)
|
||||||
|
{
|
||||||
|
$result = Engineering::BITRSHIFT(...$args);
|
||||||
|
self::assertEquals($expectedResult, $result, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBITRSHIFT()
|
||||||
|
{
|
||||||
|
return require 'data/Calculation/Engineering/BITRSHIFT.php';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerDELTA
|
* @dataProvider providerDELTA
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0b101,
|
||||||
|
[0b10101, 0b100111],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b10001000,
|
||||||
|
[0b11001000, 0b10111000],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b00001000,
|
||||||
|
[0b01001000, 0b10111000],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
['ABC', 'DEF'],
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0b1100000,
|
||||||
|
[0b11, 5],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b10100,
|
||||||
|
[0b101, 2],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
['ABC', 5],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#NUM!',
|
||||||
|
[0b01, 48],
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0b110111,
|
||||||
|
[0b10101, 0b100111],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b11111000,
|
||||||
|
[0b11001000, 0b10111000],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b11111000,
|
||||||
|
[0b01001000, 0b10111000],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#NUM!',
|
||||||
|
[12.34, 56.78],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
60,
|
||||||
|
[12.00, 56.00],
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0b101,
|
||||||
|
[0b10100, 2],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b11,
|
||||||
|
[0b110100, 4],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
['ABC', 5],
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
0b110010,
|
||||||
|
[0b10101, 0b100111],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b01110000,
|
||||||
|
[0b11001000, 0b10111000],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0b11011000,
|
||||||
|
[0b01110010, 0b10101010],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
['ABC', 'DEF'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#NUM!',
|
||||||
|
[12.00, 2.82E14],
|
||||||
|
],
|
||||||
|
];
|
Loading…
Reference in New Issue