Skip to content

Commit d0a5c66

Browse files
committed
Allow negative scale in BigDecimal::ofUnscaledValue()
1 parent 88500fc commit d0a5c66

File tree

3 files changed

+107
-32
lines changed

3 files changed

+107
-32
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## UNRELEASED (0.13.0)
6+
7+
💥 **Breaking changes**
8+
9+
- `BigDecimal::ofUnscaledValue()` no longer throws an exception if the scale is negative
10+
11+
**New features**
12+
13+
- `BigDecimal::ofUnscaledValue()` allows a negative scale (and converts the values to create a zero scale number)
14+
515
## [0.12.3](https://github.com/brick/math/releases/tag/0.12.3) - 2025-02-28
616

717
**New features**

src/BigDecimal.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,23 @@ protected static function from(BigNumber $number): static
6060
* Example: `(12345, 3)` will result in the BigDecimal `12.345`.
6161
*
6262
* @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.
63-
* @param int $scale The scale of the number, positive or zero.
64-
*
65-
* @throws \InvalidArgumentException If the scale is negative.
63+
* @param int $scale The scale of the number. If negative, the scale will be set to zero
64+
* and the unscaled value will be adjusted accordingly.
6665
*
6766
* @psalm-pure
6867
*/
6968
public static function ofUnscaledValue(BigNumber|int|float|string $value, int $scale = 0) : BigDecimal
7069
{
70+
$value = (string) BigInteger::of($value);
71+
7172
if ($scale < 0) {
72-
throw new \InvalidArgumentException('The scale cannot be negative.');
73+
if ($value !== '0') {
74+
$value .= \str_repeat('0', -$scale);
75+
}
76+
$scale = 0;
7377
}
7478

75-
return new BigDecimal((string) BigInteger::of($value), $scale);
79+
return new BigDecimal($value, $scale);
7680
}
7781

7882
/**

tests/BigDecimalTest.php

+88-27
Original file line numberDiff line numberDiff line change
@@ -269,48 +269,109 @@ public function testOfBigDecimalReturnsThis() : void
269269
* @param int|string $unscaledValue The unscaled value of the BigDecimal to create.
270270
* @param int $scale The scale of the BigDecimal to create.
271271
* @param string $expectedUnscaledValue The expected result unscaled value.
272+
* @param int $expectedScale The expected result scale.
272273
*/
273274
#[DataProvider('providerOfUnscaledValue')]
274-
public function testOfUnscaledValue(int|string $unscaledValue, int $scale, string $expectedUnscaledValue) : void
275-
{
275+
public function testOfUnscaledValue(
276+
int|string $unscaledValue,
277+
int $scale,
278+
string $expectedUnscaledValue,
279+
int $expectedScale,
280+
) : void {
276281
$number = BigDecimal::ofUnscaledValue($unscaledValue, $scale);
277-
self::assertBigDecimalInternalValues($expectedUnscaledValue, $scale, $number);
282+
self::assertBigDecimalInternalValues($expectedUnscaledValue, $expectedScale, $number);
278283
}
279284

280285
public static function providerOfUnscaledValue() : array
281286
{
282287
return [
283-
[123456789, 0, '123456789'],
284-
[123456789, 1, '123456789'],
285-
[-123456789, 0, '-123456789'],
286-
[-123456789, 1, '-123456789'],
287-
288-
['123456789012345678901234567890', 0, '123456789012345678901234567890'],
289-
['123456789012345678901234567890', 1, '123456789012345678901234567890'],
290-
['+123456789012345678901234567890', 0, '123456789012345678901234567890'],
291-
['+123456789012345678901234567890', 1, '123456789012345678901234567890'],
292-
['-123456789012345678901234567890', 0, '-123456789012345678901234567890'],
293-
['-123456789012345678901234567890', 1, '-123456789012345678901234567890'],
294-
295-
['0123456789012345678901234567890', 0, '123456789012345678901234567890'],
296-
['0123456789012345678901234567890', 1, '123456789012345678901234567890'],
297-
['+0123456789012345678901234567890', 0, '123456789012345678901234567890'],
298-
['+0123456789012345678901234567890', 1, '123456789012345678901234567890'],
299-
['-0123456789012345678901234567890', 0, '-123456789012345678901234567890'],
300-
['-0123456789012345678901234567890', 1, '-123456789012345678901234567890'],
288+
[0, -2, '0', 0],
289+
[0, -1, '0', 0],
290+
[0, 0, '0', 0],
291+
[0, 1, '0', 1],
292+
[0, 2, '0', 2],
293+
294+
[123456789, -2, '12345678900', 0],
295+
[123456789, -1, '1234567890', 0],
296+
[123456789, 0, '123456789', 0],
297+
[123456789, 1, '123456789', 1],
298+
299+
[-123456789, -2, '-12345678900', 0],
300+
[-123456789, -1, '-1234567890', 0],
301+
[-123456789, 0, '-123456789', 0],
302+
[-123456789, 1, '-123456789', 1],
303+
304+
['123456789012345678901234567890', -1, '1234567890123456789012345678900', 0],
305+
['123456789012345678901234567890', 0, '123456789012345678901234567890', 0],
306+
['123456789012345678901234567890', 1, '123456789012345678901234567890', 1],
307+
['+123456789012345678901234567890', -1, '1234567890123456789012345678900', 0],
308+
['+123456789012345678901234567890', 0, '123456789012345678901234567890', 0],
309+
['+123456789012345678901234567890', 1, '123456789012345678901234567890', 1],
310+
['-123456789012345678901234567890', -1, '-1234567890123456789012345678900', 0],
311+
['-123456789012345678901234567890', 0, '-123456789012345678901234567890', 0],
312+
['-123456789012345678901234567890', 1, '-123456789012345678901234567890', 1],
313+
314+
['0123456789012345678901234567890', -1, '1234567890123456789012345678900', 0],
315+
['0123456789012345678901234567890', 0, '123456789012345678901234567890', 0],
316+
['0123456789012345678901234567890', 1, '123456789012345678901234567890', 1],
317+
['+0123456789012345678901234567890', -1, '1234567890123456789012345678900', 0],
318+
['+0123456789012345678901234567890', 0, '123456789012345678901234567890', 0],
319+
['+0123456789012345678901234567890', 1, '123456789012345678901234567890', 1],
320+
['-0123456789012345678901234567890', -1, '-1234567890123456789012345678900', 0],
321+
['-0123456789012345678901234567890', 0, '-123456789012345678901234567890', 0],
322+
['-0123456789012345678901234567890', 1, '-123456789012345678901234567890', 1],
301323
];
302324
}
303325

304-
public function testOfUnscaledValueWithDefaultScale() : void
326+
#[DataProvider('providerOfUnscaledValueToString')]
327+
public function testOfUnscaledValueToString(string $unscaledValue, int $scale, string $expected) : void
305328
{
306-
$number = BigDecimal::ofUnscaledValue('123456789');
307-
self::assertBigDecimalInternalValues('123456789', 0, $number);
329+
self::assertSame($expected, (string) BigDecimal::ofUnscaledValue($unscaledValue, $scale));
308330
}
309331

310-
public function testOfUnscaledValueWithNegativeScaleThrowsException() : void
332+
public static function providerOfUnscaledValueToString() : array
311333
{
312-
$this->expectException(\InvalidArgumentException::class);
313-
BigDecimal::ofUnscaledValue('0', -1);
334+
return [
335+
['-1', -1, '-10'],
336+
['-1', 0, '-1'],
337+
['-1', 1, '-0.1'],
338+
339+
['-0', -1, '0'],
340+
['-0', 0, '0'],
341+
['-0', 1, '0.0'],
342+
343+
['0', -1, '0'],
344+
['0', 0, '0'],
345+
['0', 1, '0.0'],
346+
347+
['1', -1, '10'],
348+
['1', 0, '1'],
349+
['1', 1, '0.1'],
350+
351+
['-123', -3, '-123000'],
352+
['-123', -2, '-12300'],
353+
['-123', -1, '-1230'],
354+
['-123', 0, '-123'],
355+
['-123', 1, '-12.3'],
356+
['-123', 2, '-1.23'],
357+
['-123', 3, '-0.123'],
358+
['-123', 4, '-0.0123'],
359+
360+
['123', -3, '123000'],
361+
['123', -2, '12300'],
362+
['123', -1, '1230'],
363+
['123', 0, '123'],
364+
['123', 1, '12.3'],
365+
['123', 2, '1.23'],
366+
['123', 3, '0.123'],
367+
['123', 4, '0.0123'],
368+
];
369+
}
370+
371+
public function testOfUnscaledValueWithDefaultScale() : void
372+
{
373+
$number = BigDecimal::ofUnscaledValue('123456789');
374+
self::assertBigDecimalInternalValues('123456789', 0, $number);
314375
}
315376

316377
public function testZero() : void

0 commit comments

Comments
 (0)