1: <?php
2:
3: /**
4: * Hard type support
5: * For when you absolutely want to know what you are getting
6: *
7: * @author Ashley Kitson <akitson@zf4.biz>
8: * @copyright Ashley Kitson, UK, 2014
9: * @licence GPL V3 or later : http://www.gnu.org/licenses/gpl.html
10:
11: * Thanks to Florian Wolters for the inspiration
12: * @link http://github.com/FlorianWolters/PHP-Component-Number-Fraction*
13: */
14:
15: namespace chippyash\Type\Number\Rational;
16:
17: use chippyash\Type\Interfaces\GMPInterface;
18: use chippyash\Type\Number\GMPIntType;
19: use chippyash\Type\Number\Complex\GMPComplexType;
20: use chippyash\Type\BoolType;
21:
22: /**
23: * A rational number (i.e a fraction)
24: * This is the GMP type.
25: *
26: */
27: class GMPRationalType extends AbstractRationalType implements GMPInterface
28: {
29: /**
30: * Map of values for this type
31: * @var array
32: */
33: protected $valueMap = array(
34: 0 => array('name' => 'num', 'class' => 'chippyash\Type\Number\GMPIntType'),
35: 1 => array('name' => 'den', 'class' => 'chippyash\Type\Number\GMPIntType')
36: );
37:
38: /**
39: * Construct new GMP rational
40: *
41: * @param GMPIntType $num numerator
42: * @param GMPIntType $den denominator
43: * @param \chippyash\Type\BoolType $reduce -optional: default = true
44: */
45: public function __construct(GMPIntType $num, GMPIntType $den, BoolType $reduce = null)
46: {
47: if ($reduce != null) {
48: $this->reduce = $reduce();
49: }
50: parent::__construct($num, $den);
51: }
52:
53: /**
54: * Get the value of the object typed properly
55: * as a PHP Native type
56: *
57: * @return integer|float
58: */
59: public function get()
60: {
61: if ($this->isInteger()) {
62: /** @noinspection PhpUndefinedMethodInspection */
63: return $this->value['num']->get();
64: } else {
65: $num = intval(gmp_strval($this->value['num']->gmp()));
66: $den = intval(gmp_strval($this->value['den']->gmp()));
67: return $num/$den;
68: }
69: }
70:
71: /**
72: * Return the value of number as a gmp resource, object or array of same
73: *
74: * @return array [numerator, denominator]
75: */
76: public function gmp()
77: {
78: return array($this->value['num']->gmp(), $this->value['den']->gmp());
79: }
80:
81: /**
82: * Return number as GMPIntType number.
83: * Will return floor(n/d)
84: *
85: * @return \chippyash\Type\Number\GMPIntType
86: */
87: public function asGMPIntType()
88: {
89: return new GMPIntType(floor($this->get()));
90: }
91:
92: /**
93: * Return the number as a GMPComplex number i.e. n+0i
94: *
95: * @return \chippyash\Type\Number\Complex\GMPComplexType
96: */
97: public function asGMPComplex()
98: {
99: return new GMPComplexType(
100: new GMPRationalType(clone $this->numerator(), clone $this->denominator()),
101: new GMPRationalType(new GMPIntType(0), new GMPIntType(1))
102: );
103: }
104:
105: /**
106: * Return number as GMPRational number.
107: * NB, numerator and denominator will be caste as IntTypes
108: *
109: * @return \chippyash\Type\Number\Rational\GMPRationalType
110: */
111: public function asGMPRational()
112: {
113: return clone $this;
114: }
115:
116: /**
117: * Return number as native Rational number.
118: * NB, numerator and denominator will be caste as IntTypes
119: *
120: * @return \chippyash\Type\Number\Rational\RationalType
121: */
122: public function asRational()
123: {
124: return new RationalType(
125: $this->value['num']->asIntType(),
126: $this->value['den']->asIntType()
127: );
128: }
129:
130: /**
131: * Reduce this number to it's lowest form
132: */
133: protected function reduce()
134: {
135: $gcd = gmp_gcd($this->value['num']->gmp(), $this->value['den']->gmp());
136: if (gmp_cmp($gcd, 1) > 0) {
137: $this->value['num']->set(gmp_div_q($this->value['num']->gmp(), $gcd));
138: $this->value['den']->set(gmp_div_q($this->value['den']->gmp(), $gcd));
139: }
140: }
141: }
142: