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:
Mark Baker 2018-07-22 22:16:34 +01:00 committed by GitHub
parent 9b44cf3418
commit 67cdee6033
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 400 additions and 2 deletions

View File

@ -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)

View File

@ -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'],

View File

@ -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.
* *

View File

@ -32,6 +32,11 @@ BIN2DEC
BIN2HEX BIN2HEX
BIN2OCT BIN2OCT
BINOMDIST BINOMDIST
BITAND
BITLSHIFT
BITOR
BITRSHIFT
BITXOR
CEILING CEILING
CELL CELL
CHAR CHAR

View File

@ -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
* *

View File

@ -0,0 +1,20 @@
<?php
return [
[
0b101,
[0b10101, 0b100111],
],
[
0b10001000,
[0b11001000, 0b10111000],
],
[
0b00001000,
[0b01001000, 0b10111000],
],
[
'#VALUE!',
['ABC', 'DEF'],
],
];

View File

@ -0,0 +1,20 @@
<?php
return [
[
0b1100000,
[0b11, 5],
],
[
0b10100,
[0b101, 2],
],
[
'#VALUE!',
['ABC', 5],
],
[
'#NUM!',
[0b01, 48],
],
];

View File

@ -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],
],
];

View File

@ -0,0 +1,16 @@
<?php
return [
[
0b101,
[0b10100, 2],
],
[
0b11,
[0b110100, 4],
],
[
'#VALUE!',
['ABC', 5],
],
];

View File

@ -0,0 +1,24 @@
<?php
return [
[
0b110010,
[0b10101, 0b100111],
],
[
0b01110000,
[0b11001000, 0b10111000],
],
[
0b11011000,
[0b01110010, 0b10101010],
],
[
'#VALUE!',
['ABC', 'DEF'],
],
[
'#NUM!',
[12.00, 2.82E14],
],
];