Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
louisgab committed Dec 22, 2020
0 parents commit 98728e4
Show file tree
Hide file tree
Showing 13 changed files with 1,548 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* text=auto eol=lf

/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/tests export-ignore
CHANGELOG.md export-ignore
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/vendor
/composer.lock
.phpunit.result.cache
.php_cs.cache
.idea
.vscode
.DS_Store
261 changes: 261 additions & 0 deletions .php_cs.dist

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.md
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog

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

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.1] - 2020-12-22

### Added

- Number immutable value object
82 changes: 82 additions & 0 deletions DOCS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Documentation

## Instanciation

`Number::of(any)` accepts any numeric value like floats, integers and even strings or other Number instances

e.g: `Number::of("1.5")`, `Number::of(1/3)`, `Number::of(1)`, `Number::of(Number::of(12.8))` are valid and correctly handled

On the other hand, the strings must be sane

e.g `Number::of('1/3')`, `Number::of('1,2')`, `Number::of('1.5€')` will throw an exception

Basic instances are already built-in:

- `Number::zero()` alias for Number::of(0)
- `Number::one()` alias for Number::of(1)
- `Number::ten()` alias for Number::of(10)
- `Number::hundred()` alias for Number::of(100)
- `Number::thousand()` alias for Number::of(1000)

## Collections

- `Number::sum(...any)` return a Number which values to the sum of the values in the collection
- `Number::max(...any)` return a Number which values to the max value in the collection
- `Number::min(...any)` return a Number which values to the min value in the collection
- `Number::average(...any)` return a Number which values to the average value of the collection

Those methods accepts a list of valid values (e.g: `Number::sum("2", 4, 1/2)`) as well as an iterable object (e.g: `Number::sum(["2", 4, 1/2])`)

## Methods

### Basic maths methods:

- `plus(any)` returns a Number which values to the sum between the two Numbers
- `minus(any)` returns a Number which values to the difference between the two Numbers
- `multiply(any)` returns a Number which values to the multiplication between the two Numbers
- `divide(any)` returns a Number which values to the division between the two Numbers
- `power(exponent)` returns a Number which values powered to the exponent
- `square()` alias for power(2)
- `cube()` alias for power(3)
- `absolute()` returns a Number which value is positive
- `negate()` returns a Number which value will be positive if was negative, negative if positive
- `inverse()` returns a Number which values to one over the number
- `round(precision, mode)` returns a Number which values will rounded according to parameters, defaults to 15 digits and up
- `round(precision)` returns a Number which decimals will be truncated according to precision without any rounding

### Comparison methods:

- `compare(any)` returns -1 if Number is less, 1 if Number is greater and 0 if Numbers are equal, like strcmp does for strings
- `equals(any)` returns whether the two Numbers are equal. It handles floats epsilon comparison.
- `isDifferent(any)` returns the inverse of equals
- `isGreater(any)` returns the strict superiority comparison result
- `isGreaterOrEqual(any)` returns the superiority comparison result
- `isLess(any)` returns the strict inferiority comparison result
- `isLessOrEqual(any)` returns the inferiority comparison result

### Other useful methods:

- `isPositive()` returns whether the Number value is positive or not
- `isNegative()` returns whether the Number value is negative or not
- `isZero()` returns whether the Number value is equal to zero
- `isWhole()` returns whether the Number has a decimal part
- `decimalPlaces()` returns a count of the decimal part digits
- `apply(callback)` returns the callback result, useful for custom functions
- `when(bool, callback)` returns the callback result if the condition is truthy
- `format(locale, decimals, forceDecimals)` returns the display format of the number in the desired locale (not for database storage!)


## Accessors
- `get()` returns the raw internal float value (for debug purposes)
- `value()` returns the float value, preferred over value(), because the format will be right (no strange values like -0.0)
- `sign()` returns `+` or `-`. N.B: Zero will be positive.
- `wholePart()` returns the left part of the floating point (e.g 3.52 is 3)
- `decimalPart()` returns the right part of the floating point (e.g 3.52 is 0.52)

All accessors can be retrieved as properties like `->value` or `->sign`.


## Warning

While floats you be fine for most usages, please read [What Every Programmer Should Know About Floating-Point Arithmetic](https://floating-point-gui.de/), so you will be aware of its limits. Calc tries to overcome it as much as possible (see the `equals()` method implementation), but still some edge cases can occur.
If so, new tests are welcomed (please PR).
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Louis-Gabriel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
87 changes: 87 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Calc

[![Packagist Version](https://img.shields.io/packagist/v/louisgab/php-calc.svg?style=flat-square)](https://packagist.org/packages/louisgab/php-calc)
[![Packagist Downloads](https://img.shields.io/packagist/dt/louisgab/php-calc.svg?style=flat-square)](https://packagist.org/packages/louisgab/php-calc)
[![GitHub license](https://img.shields.io/github/license/louisgab/php-calc.svg?style=flat-square)](https://github.com/louisgab/php-calc/blob/master/LICENSE)

💯 Simple fluent float manipulation library.

Calc aims to provide tools for easy and readable calculations, without any dependency.
It comes with `Number` which is an immutable value object that enables fluent float manipulations.

## Why

If you ever worked with a codebase full of that kind of crap:

```php
$result = round(($b != 0 ? ((1+$a)/$b) : $c)*0.25, 2)
```

I'm sure you will enjoy that:

```php
$result = Number::of($b)
->when(Number::of($b)->isZero(),
fn($b) => $c
fn($b) => Number::one()->plus($a)->divide($b),
)
->multiply(0.25)
->round(2)
->value()
```

You may think it's like [brick/math](https://github.com/brick/math), which is a really great package, but Calc serves a different purpose.
If floats are good enough for you - and unless you're dealing with sensible data like accounting or science, it should be - then using GMP or bcmath is overkill.

That's what Calc is made for, still using floats while enjoying nice readability.
Another good point is that it handles floating point problems (e.g `0.1 + 0.2 == 0.3 // false`) as much as possible, so you don't have to think about it each time (and if you are working with junior developers, it will save them from having problems they didn't even know existed!).

## Install

Via composer:

```bash
composer require louisgab/php-calc
```

## Usage
Simple as:
```php
use Louisgab\Calc\Number;

Number::of($anything);
```

And good as :
```php
public function carsNeeded(Number $people, Number $placesPerCar): int
{
return $people->divide($placesPerCar)->round(0)->toInt();
}
```

Please see [DOCS](DOCS.md)

## Testing

```bash
composer test
```

## Roadmap

- [x] `Number`
- [ ] `Fraction`
- [ ] `Percentage`

## Changelog

Please see [CHANGELOG](CHANGELOG.md)

## Contributing

Highly welcomed!

## License

Please see [The MIT License (MIT)](LICENSE.md).
36 changes: 36 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "louisgab/php-calc",
"description": "Simple fluent float manipulation library",
"type": "library",
"keywords": [
"php", "number", "float", "fluent"
],
"homepage": "https://github.com/louisgab/number",
"license": "MIT",
"author": "Louis Gabriel <[email protected]>",
"require": {
"php": "^7.4"
},
"require-dev": {
"phpunit/phpunit": "^9"
},
"autoload": {
"psr-4": {
"Louisgab\\Calc\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Louisgab\\Calc\\Tests\\": "tests"
}
},
"scripts": {
"test": "vendor/bin/phpunit --testdox --colors=always",
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}
24 changes: 24 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
Loading

0 comments on commit 98728e4

Please sign in to comment.