Completed
Push — develop ( 03f96a...8c66af )
by Adrien
19:36
created

Engineering::OCTTOBIN()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 15
Ratio 100 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 2
dl 15
loc 15
rs 9.4285
c 0
b 0
f 0
ccs 9
cts 9
cp 1
crap 3
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
/* EULER */
6 1
define('EULER', 2.71828182845904523536);
7
8
/**
9
 * Copyright (c) 2006 - 2016 PhpSpreadsheet.
10
 *
11
 * This library is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13
 * License as published by the Free Software Foundation; either
14
 * version 2.1 of the License, or (at your option) any later version.
15
 *
16
 * This library is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with this library; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
 *
25
 * @category    PhpSpreadsheet
26
 *
27
 * @copyright    Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
28
 * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
29
 */
30
class Engineering
31
{
32
    /**
33
     * Details of the Units of measure that can be used in CONVERTUOM().
34
     *
35
     * @var mixed[]
36
     */
37
    private static $conversionUnits = [
38
        'g' => ['Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => true],
39
        'sg' => ['Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => false],
40
        'lbm' => ['Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false],
41
        'u' => ['Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true],
42
        'ozm' => ['Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false],
43
        'm' => ['Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => true],
44
        'mi' => ['Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => false],
45
        'Nmi' => ['Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false],
46
        'in' => ['Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => false],
47
        'ft' => ['Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => false],
48
        'yd' => ['Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => false],
49
        'ang' => ['Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => true],
50
        'Pica' => ['Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false],
51
        'yr' => ['Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => false],
52
        'day' => ['Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => false],
53
        'hr' => ['Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => false],
54
        'mn' => ['Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => false],
55
        'sec' => ['Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => true],
56
        'Pa' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true],
57
        'p' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true],
58
        'atm' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true],
59
        'at' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true],
60
        'mmHg' => ['Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true],
61
        'N' => ['Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => true],
62
        'dyn' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true],
63
        'dy' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true],
64
        'lbf' => ['Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => false],
65
        'J' => ['Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => true],
66
        'e' => ['Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => true],
67
        'c' => ['Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true],
68
        'cal' => ['Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => true],
69
        'eV' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true],
70
        'ev' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true],
71
        'HPh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false],
72
        'hh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false],
73
        'Wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true],
74
        'wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true],
75
        'flb' => ['Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false],
76
        'BTU' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false],
77
        'btu' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false],
78
        'HP' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false],
79
        'h' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false],
80
        'W' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true],
81
        'w' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true],
82
        'T' => ['Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => true],
83
        'ga' => ['Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => true],
84
        'C' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false],
85
        'cel' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false],
86
        'F' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false],
87
        'fah' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false],
88
        'K' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false],
89
        'kel' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false],
90
        'tsp' => ['Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false],
91
        'tbs' => ['Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false],
92
        'oz' => ['Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false],
93
        'cup' => ['Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => false],
94
        'pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false],
95
        'us_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false],
96
        'uk_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false],
97
        'qt' => ['Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => false],
98
        'gal' => ['Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => false],
99
        'l' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true],
100
        'lt' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true],
101
    ];
102
103
    /**
104
     * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
105
     *
106
     * @var mixed[]
107
     */
108
    private static $conversionMultipliers = [
109
        'Y' => ['multiplier' => 1E24, 'name' => 'yotta'],
110
        'Z' => ['multiplier' => 1E21, 'name' => 'zetta'],
111
        'E' => ['multiplier' => 1E18, 'name' => 'exa'],
112
        'P' => ['multiplier' => 1E15, 'name' => 'peta'],
113
        'T' => ['multiplier' => 1E12, 'name' => 'tera'],
114
        'G' => ['multiplier' => 1E9, 'name' => 'giga'],
115
        'M' => ['multiplier' => 1E6, 'name' => 'mega'],
116
        'k' => ['multiplier' => 1E3, 'name' => 'kilo'],
117
        'h' => ['multiplier' => 1E2, 'name' => 'hecto'],
118
        'e' => ['multiplier' => 1E1, 'name' => 'deka'],
119
        'd' => ['multiplier' => 1E-1, 'name' => 'deci'],
120
        'c' => ['multiplier' => 1E-2, 'name' => 'centi'],
121
        'm' => ['multiplier' => 1E-3, 'name' => 'milli'],
122
        'u' => ['multiplier' => 1E-6, 'name' => 'micro'],
123
        'n' => ['multiplier' => 1E-9, 'name' => 'nano'],
124
        'p' => ['multiplier' => 1E-12, 'name' => 'pico'],
125
        'f' => ['multiplier' => 1E-15, 'name' => 'femto'],
126
        'a' => ['multiplier' => 1E-18, 'name' => 'atto'],
127
        'z' => ['multiplier' => 1E-21, 'name' => 'zepto'],
128
        'y' => ['multiplier' => 1E-24, 'name' => 'yocto'],
129
    ];
130
131
    /**
132
     * Details of the Units of measure conversion factors, organised by group.
133
     *
134
     * @var mixed[]
135
     */
136
    private static $unitConversions = [
137
        'Mass' => [
138
            'g' => [
139
                'g' => 1.0,
140
                'sg' => 6.85220500053478E-05,
141
                'lbm' => 2.20462291469134E-03,
142
                'u' => 6.02217000000000E+23,
143
                'ozm' => 3.52739718003627E-02,
144
            ],
145
            'sg' => [
146
                'g' => 1.45938424189287E+04,
147
                'sg' => 1.0,
148
                'lbm' => 3.21739194101647E+01,
149
                'u' => 8.78866000000000E+27,
150
                'ozm' => 5.14782785944229E+02,
151
            ],
152
            'lbm' => [
153
                'g' => 4.5359230974881148E+02,
154
                'sg' => 3.10810749306493E-02,
155
                'lbm' => 1.0,
156
                'u' => 2.73161000000000E+26,
157
                'ozm' => 1.60000023429410E+01,
158
            ],
159
            'u' => [
160
                'g' => 1.66053100460465E-24,
161
                'sg' => 1.13782988532950E-28,
162
                'lbm' => 3.66084470330684E-27,
163
                'u' => 1.0,
164
                'ozm' => 5.85735238300524E-26,
165
            ],
166
            'ozm' => [
167
                'g' => 2.83495152079732E+01,
168
                'sg' => 1.94256689870811E-03,
169
                'lbm' => 6.24999908478882E-02,
170
                'u' => 1.70725600000000E+25,
171
                'ozm' => 1.0,
172
            ],
173
        ],
174
        'Distance' => [
175
            'm' => [
176
                'm' => 1.0,
177
                'mi' => 6.21371192237334E-04,
178
                'Nmi' => 5.39956803455724E-04,
179
                'in' => 3.93700787401575E+01,
180
                'ft' => 3.28083989501312E+00,
181
                'yd' => 1.09361329797891E+00,
182
                'ang' => 1.00000000000000E+10,
183
                'Pica' => 2.83464566929116E+03,
184
            ],
185
            'mi' => [
186
                'm' => 1.60934400000000E+03,
187
                'mi' => 1.0,
188
                'Nmi' => 8.68976241900648E-01,
189
                'in' => 6.33600000000000E+04,
190
                'ft' => 5.28000000000000E+03,
191
                'yd' => 1.76000000000000E+03,
192
                'ang' => 1.60934400000000E+13,
193
                'Pica' => 4.56191999999971E+06,
194
            ],
195
            'Nmi' => [
196
                'm' => 1.85200000000000E+03,
197
                'mi' => 1.15077944802354E+00,
198
                'Nmi' => 1.0,
199
                'in' => 7.29133858267717E+04,
200
                'ft' => 6.07611548556430E+03,
201
                'yd' => 2.02537182785694E+03,
202
                'ang' => 1.85200000000000E+13,
203
                'Pica' => 5.24976377952723E+06,
204
            ],
205
            'in' => [
206
                'm' => 2.54000000000000E-02,
207
                'mi' => 1.57828282828283E-05,
208
                'Nmi' => 1.37149028077754E-05,
209
                'in' => 1.0,
210
                'ft' => 8.33333333333333E-02,
211
                'yd' => 2.77777777686643E-02,
212
                'ang' => 2.54000000000000E+08,
213
                'Pica' => 7.19999999999955E+01,
214
            ],
215
            'ft' => [
216
                'm' => 3.04800000000000E-01,
217
                'mi' => 1.89393939393939E-04,
218
                'Nmi' => 1.64578833693305E-04,
219
                'in' => 1.20000000000000E+01,
220
                'ft' => 1.0,
221
                'yd' => 3.33333333223972E-01,
222
                'ang' => 3.04800000000000E+09,
223
                'Pica' => 8.63999999999946E+02,
224
            ],
225
            'yd' => [
226
                'm' => 9.14400000300000E-01,
227
                'mi' => 5.68181818368230E-04,
228
                'Nmi' => 4.93736501241901E-04,
229
                'in' => 3.60000000118110E+01,
230
                'ft' => 3.00000000000000E+00,
231
                'yd' => 1.0,
232
                'ang' => 9.14400000300000E+09,
233
                'Pica' => 2.59200000085023E+03,
234
            ],
235
            'ang' => [
236
                'm' => 1.00000000000000E-10,
237
                'mi' => 6.21371192237334E-14,
238
                'Nmi' => 5.39956803455724E-14,
239
                'in' => 3.93700787401575E-09,
240
                'ft' => 3.28083989501312E-10,
241
                'yd' => 1.09361329797891E-10,
242
                'ang' => 1.0,
243
                'Pica' => 2.83464566929116E-07,
244
            ],
245
            'Pica' => [
246
                'm' => 3.52777777777800E-04,
247
                'mi' => 2.19205948372629E-07,
248
                'Nmi' => 1.90484761219114E-07,
249
                'in' => 1.38888888888898E-02,
250
                'ft' => 1.15740740740748E-03,
251
                'yd' => 3.85802469009251E-04,
252
                'ang' => 3.52777777777800E+06,
253
                'Pica' => 1.0,
254
            ],
255
        ],
256
        'Time' => [
257
            'yr' => [
258
                'yr' => 1.0,
259
                'day' => 365.25,
260
                'hr' => 8766.0,
261
                'mn' => 525960.0,
262
                'sec' => 31557600.0,
263
            ],
264
            'day' => [
265
                'yr' => 2.73785078713210E-03,
266
                'day' => 1.0,
267
                'hr' => 24.0,
268
                'mn' => 1440.0,
269
                'sec' => 86400.0,
270
            ],
271
            'hr' => [
272
                'yr' => 1.14077116130504E-04,
273
                'day' => 4.16666666666667E-02,
274
                'hr' => 1.0,
275
                'mn' => 60.0,
276
                'sec' => 3600.0,
277
            ],
278
            'mn' => [
279
                'yr' => 1.90128526884174E-06,
280
                'day' => 6.94444444444444E-04,
281
                'hr' => 1.66666666666667E-02,
282
                'mn' => 1.0,
283
                'sec' => 60.0,
284
            ],
285
            'sec' => [
286
                'yr' => 3.16880878140289E-08,
287
                'day' => 1.15740740740741E-05,
288
                'hr' => 2.77777777777778E-04,
289
                'mn' => 1.66666666666667E-02,
290
                'sec' => 1.0,
291
            ],
292
        ],
293
        'Pressure' => [
294
            'Pa' => [
295
                'Pa' => 1.0,
296
                'p' => 1.0,
297
                'atm' => 9.86923299998193E-06,
298
                'at' => 9.86923299998193E-06,
299
                'mmHg' => 7.50061707998627E-03,
300
            ],
301
            'p' => [
302
                'Pa' => 1.0,
303
                'p' => 1.0,
304
                'atm' => 9.86923299998193E-06,
305
                'at' => 9.86923299998193E-06,
306
                'mmHg' => 7.50061707998627E-03,
307
            ],
308
            'atm' => [
309
                'Pa' => 1.01324996583000E+05,
310
                'p' => 1.01324996583000E+05,
311
                'atm' => 1.0,
312
                'at' => 1.0,
313
                'mmHg' => 760.0,
314
            ],
315
            'at' => [
316
                'Pa' => 1.01324996583000E+05,
317
                'p' => 1.01324996583000E+05,
318
                'atm' => 1.0,
319
                'at' => 1.0,
320
                'mmHg' => 760.0,
321
            ],
322
            'mmHg' => [
323
                'Pa' => 1.33322363925000E+02,
324
                'p' => 1.33322363925000E+02,
325
                'atm' => 1.31578947368421E-03,
326
                'at' => 1.31578947368421E-03,
327
                'mmHg' => 1.0,
328
            ],
329
        ],
330
        'Force' => [
331
            'N' => [
332
                'N' => 1.0,
333
                'dyn' => 1.0E+5,
334
                'dy' => 1.0E+5,
335
                'lbf' => 2.24808923655339E-01,
336
            ],
337
            'dyn' => [
338
                'N' => 1.0E-5,
339
                'dyn' => 1.0,
340
                'dy' => 1.0,
341
                'lbf' => 2.24808923655339E-06,
342
            ],
343
            'dy' => [
344
                'N' => 1.0E-5,
345
                'dyn' => 1.0,
346
                'dy' => 1.0,
347
                'lbf' => 2.24808923655339E-06,
348
            ],
349
            'lbf' => [
350
                'N' => 4.448222,
351
                'dyn' => 4.448222E+5,
352
                'dy' => 4.448222E+5,
353
                'lbf' => 1.0,
354
            ],
355
        ],
356
        'Energy' => [
357
            'J' => [
358
                'J' => 1.0,
359
                'e' => 9.99999519343231E+06,
360
                'c' => 2.39006249473467E-01,
361
                'cal' => 2.38846190642017E-01,
362
                'eV' => 6.24145700000000E+18,
363
                'ev' => 6.24145700000000E+18,
364
                'HPh' => 3.72506430801000E-07,
365
                'hh' => 3.72506430801000E-07,
366
                'Wh' => 2.77777916238711E-04,
367
                'wh' => 2.77777916238711E-04,
368
                'flb' => 2.37304222192651E+01,
369
                'BTU' => 9.47815067349015E-04,
370
                'btu' => 9.47815067349015E-04,
371
            ],
372
            'e' => [
373
                'J' => 1.00000048065700E-07,
374
                'e' => 1.0,
375
                'c' => 2.39006364353494E-08,
376
                'cal' => 2.38846305445111E-08,
377
                'eV' => 6.24146000000000E+11,
378
                'ev' => 6.24146000000000E+11,
379
                'HPh' => 3.72506609848824E-14,
380
                'hh' => 3.72506609848824E-14,
381
                'Wh' => 2.77778049754611E-11,
382
                'wh' => 2.77778049754611E-11,
383
                'flb' => 2.37304336254586E-06,
384
                'BTU' => 9.47815522922962E-11,
385
                'btu' => 9.47815522922962E-11,
386
            ],
387
            'c' => [
388
                'J' => 4.18399101363672E+00,
389
                'e' => 4.18398900257312E+07,
390
                'c' => 1.0,
391
                'cal' => 9.99330315287563E-01,
392
                'eV' => 2.61142000000000E+19,
393
                'ev' => 2.61142000000000E+19,
394
                'HPh' => 1.55856355899327E-06,
395
                'hh' => 1.55856355899327E-06,
396
                'Wh' => 1.16222030532950E-03,
397
                'wh' => 1.16222030532950E-03,
398
                'flb' => 9.92878733152102E+01,
399
                'BTU' => 3.96564972437776E-03,
400
                'btu' => 3.96564972437776E-03,
401
            ],
402
            'cal' => [
403
                'J' => 4.18679484613929E+00,
404
                'e' => 4.18679283372801E+07,
405
                'c' => 1.00067013349059E+00,
406
                'cal' => 1.0,
407
                'eV' => 2.61317000000000E+19,
408
                'ev' => 2.61317000000000E+19,
409
                'HPh' => 1.55960800463137E-06,
410
                'hh' => 1.55960800463137E-06,
411
                'Wh' => 1.16299914807955E-03,
412
                'wh' => 1.16299914807955E-03,
413
                'flb' => 9.93544094443283E+01,
414
                'BTU' => 3.96830723907002E-03,
415
                'btu' => 3.96830723907002E-03,
416
            ],
417
            'eV' => [
418
                'J' => 1.60219000146921E-19,
419
                'e' => 1.60218923136574E-12,
420
                'c' => 3.82933423195043E-20,
421
                'cal' => 3.82676978535648E-20,
422
                'eV' => 1.0,
423
                'ev' => 1.0,
424
                'HPh' => 5.96826078912344E-26,
425
                'hh' => 5.96826078912344E-26,
426
                'Wh' => 4.45053000026614E-23,
427
                'wh' => 4.45053000026614E-23,
428
                'flb' => 3.80206452103492E-18,
429
                'BTU' => 1.51857982414846E-22,
430
                'btu' => 1.51857982414846E-22,
431
            ],
432
            'ev' => [
433
                'J' => 1.60219000146921E-19,
434
                'e' => 1.60218923136574E-12,
435
                'c' => 3.82933423195043E-20,
436
                'cal' => 3.82676978535648E-20,
437
                'eV' => 1.0,
438
                'ev' => 1.0,
439
                'HPh' => 5.96826078912344E-26,
440
                'hh' => 5.96826078912344E-26,
441
                'Wh' => 4.45053000026614E-23,
442
                'wh' => 4.45053000026614E-23,
443
                'flb' => 3.80206452103492E-18,
444
                'BTU' => 1.51857982414846E-22,
445
                'btu' => 1.51857982414846E-22,
446
            ],
447
            'HPh' => [
448
                'J' => 2.68451741316170E+06,
449
                'e' => 2.68451612283024E+13,
450
                'c' => 6.41616438565991E+05,
451
                'cal' => 6.41186757845835E+05,
452
                'eV' => 1.67553000000000E+25,
453
                'ev' => 1.67553000000000E+25,
454
                'HPh' => 1.0,
455
                'hh' => 1.0,
456
                'Wh' => 7.45699653134593E+02,
457
                'wh' => 7.45699653134593E+02,
458
                'flb' => 6.37047316692964E+07,
459
                'BTU' => 2.54442605275546E+03,
460
                'btu' => 2.54442605275546E+03,
461
            ],
462
            'hh' => [
463
                'J' => 2.68451741316170E+06,
464
                'e' => 2.68451612283024E+13,
465
                'c' => 6.41616438565991E+05,
466
                'cal' => 6.41186757845835E+05,
467
                'eV' => 1.67553000000000E+25,
468
                'ev' => 1.67553000000000E+25,
469
                'HPh' => 1.0,
470
                'hh' => 1.0,
471
                'Wh' => 7.45699653134593E+02,
472
                'wh' => 7.45699653134593E+02,
473
                'flb' => 6.37047316692964E+07,
474
                'BTU' => 2.54442605275546E+03,
475
                'btu' => 2.54442605275546E+03,
476
            ],
477
            'Wh' => [
478
                'J' => 3.59999820554720E+03,
479
                'e' => 3.59999647518369E+10,
480
                'c' => 8.60422069219046E+02,
481
                'cal' => 8.59845857713046E+02,
482
                'eV' => 2.24692340000000E+22,
483
                'ev' => 2.24692340000000E+22,
484
                'HPh' => 1.34102248243839E-03,
485
                'hh' => 1.34102248243839E-03,
486
                'Wh' => 1.0,
487
                'wh' => 1.0,
488
                'flb' => 8.54294774062316E+04,
489
                'BTU' => 3.41213254164705E+00,
490
                'btu' => 3.41213254164705E+00,
491
            ],
492
            'wh' => [
493
                'J' => 3.59999820554720E+03,
494
                'e' => 3.59999647518369E+10,
495
                'c' => 8.60422069219046E+02,
496
                'cal' => 8.59845857713046E+02,
497
                'eV' => 2.24692340000000E+22,
498
                'ev' => 2.24692340000000E+22,
499
                'HPh' => 1.34102248243839E-03,
500
                'hh' => 1.34102248243839E-03,
501
                'Wh' => 1.0,
502
                'wh' => 1.0,
503
                'flb' => 8.54294774062316E+04,
504
                'BTU' => 3.41213254164705E+00,
505
                'btu' => 3.41213254164705E+00,
506
            ],
507
            'flb' => [
508
                'J' => 4.21400003236424E-02,
509
                'e' => 4.21399800687660E+05,
510
                'c' => 1.00717234301644E-02,
511
                'cal' => 1.00649785509554E-02,
512
                'eV' => 2.63015000000000E+17,
513
                'ev' => 2.63015000000000E+17,
514
                'HPh' => 1.56974211145130E-08,
515
                'hh' => 1.56974211145130E-08,
516
                'Wh' => 1.17055614802000E-05,
517
                'wh' => 1.17055614802000E-05,
518
                'flb' => 1.0,
519
                'BTU' => 3.99409272448406E-05,
520
                'btu' => 3.99409272448406E-05,
521
            ],
522
            'BTU' => [
523
                'J' => 1.05505813786749E+03,
524
                'e' => 1.05505763074665E+10,
525
                'c' => 2.52165488508168E+02,
526
                'cal' => 2.51996617135510E+02,
527
                'eV' => 6.58510000000000E+21,
528
                'ev' => 6.58510000000000E+21,
529
                'HPh' => 3.93015941224568E-04,
530
                'hh' => 3.93015941224568E-04,
531
                'Wh' => 2.93071851047526E-01,
532
                'wh' => 2.93071851047526E-01,
533
                'flb' => 2.50369750774671E+04,
534
                'BTU' => 1.0,
535
                'btu' => 1.0,
536
            ],
537
            'btu' => [
538
                'J' => 1.05505813786749E+03,
539
                'e' => 1.05505763074665E+10,
540
                'c' => 2.52165488508168E+02,
541
                'cal' => 2.51996617135510E+02,
542
                'eV' => 6.58510000000000E+21,
543
                'ev' => 6.58510000000000E+21,
544
                'HPh' => 3.93015941224568E-04,
545
                'hh' => 3.93015941224568E-04,
546
                'Wh' => 2.93071851047526E-01,
547
                'wh' => 2.93071851047526E-01,
548
                'flb' => 2.50369750774671E+04,
549
                'BTU' => 1.0,
550
                'btu' => 1.0,
551
            ],
552
        ],
553
        'Power' => [
554
            'HP' => [
555
                'HP' => 1.0,
556
                'h' => 1.0,
557
                'W' => 7.45701000000000E+02,
558
                'w' => 7.45701000000000E+02,
559
            ],
560
            'h' => [
561
                'HP' => 1.0,
562
                'h' => 1.0,
563
                'W' => 7.45701000000000E+02,
564
                'w' => 7.45701000000000E+02,
565
            ],
566
            'W' => [
567
                'HP' => 1.34102006031908E-03,
568
                'h' => 1.34102006031908E-03,
569
                'W' => 1.0,
570
                'w' => 1.0,
571
            ],
572
            'w' => [
573
                'HP' => 1.34102006031908E-03,
574
                'h' => 1.34102006031908E-03,
575
                'W' => 1.0,
576
                'w' => 1.0,
577
            ],
578
        ],
579
        'Magnetism' => [
580
            'T' => [
581
                'T' => 1.0,
582
                'ga' => 10000.0,
583
            ],
584
            'ga' => [
585
                'T' => 0.0001,
586
                'ga' => 1.0,
587
            ],
588
        ],
589
        'Liquid' => [
590
            'tsp' => [
591
                'tsp' => 1.0,
592
                'tbs' => 3.33333333333333E-01,
593
                'oz' => 1.66666666666667E-01,
594
                'cup' => 2.08333333333333E-02,
595
                'pt' => 1.04166666666667E-02,
596
                'us_pt' => 1.04166666666667E-02,
597
                'uk_pt' => 8.67558516821960E-03,
598
                'qt' => 5.20833333333333E-03,
599
                'gal' => 1.30208333333333E-03,
600
                'l' => 4.92999408400710E-03,
601
                'lt' => 4.92999408400710E-03,
602
            ],
603
            'tbs' => [
604
                'tsp' => 3.00000000000000E+00,
605
                'tbs' => 1.0,
606
                'oz' => 5.00000000000000E-01,
607
                'cup' => 6.25000000000000E-02,
608
                'pt' => 3.12500000000000E-02,
609
                'us_pt' => 3.12500000000000E-02,
610
                'uk_pt' => 2.60267555046588E-02,
611
                'qt' => 1.56250000000000E-02,
612
                'gal' => 3.90625000000000E-03,
613
                'l' => 1.47899822520213E-02,
614
                'lt' => 1.47899822520213E-02,
615
            ],
616
            'oz' => [
617
                'tsp' => 6.00000000000000E+00,
618
                'tbs' => 2.00000000000000E+00,
619
                'oz' => 1.0,
620
                'cup' => 1.25000000000000E-01,
621
                'pt' => 6.25000000000000E-02,
622
                'us_pt' => 6.25000000000000E-02,
623
                'uk_pt' => 5.20535110093176E-02,
624
                'qt' => 3.12500000000000E-02,
625
                'gal' => 7.81250000000000E-03,
626
                'l' => 2.95799645040426E-02,
627
                'lt' => 2.95799645040426E-02,
628
            ],
629
            'cup' => [
630
                'tsp' => 4.80000000000000E+01,
631
                'tbs' => 1.60000000000000E+01,
632
                'oz' => 8.00000000000000E+00,
633
                'cup' => 1.0,
634
                'pt' => 5.00000000000000E-01,
635
                'us_pt' => 5.00000000000000E-01,
636
                'uk_pt' => 4.16428088074541E-01,
637
                'qt' => 2.50000000000000E-01,
638
                'gal' => 6.25000000000000E-02,
639
                'l' => 2.36639716032341E-01,
640
                'lt' => 2.36639716032341E-01,
641
            ],
642
            'pt' => [
643
                'tsp' => 9.60000000000000E+01,
644
                'tbs' => 3.20000000000000E+01,
645
                'oz' => 1.60000000000000E+01,
646
                'cup' => 2.00000000000000E+00,
647
                'pt' => 1.0,
648
                'us_pt' => 1.0,
649
                'uk_pt' => 8.32856176149081E-01,
650
                'qt' => 5.00000000000000E-01,
651
                'gal' => 1.25000000000000E-01,
652
                'l' => 4.73279432064682E-01,
653
                'lt' => 4.73279432064682E-01,
654
            ],
655
            'us_pt' => [
656
                'tsp' => 9.60000000000000E+01,
657
                'tbs' => 3.20000000000000E+01,
658
                'oz' => 1.60000000000000E+01,
659
                'cup' => 2.00000000000000E+00,
660
                'pt' => 1.0,
661
                'us_pt' => 1.0,
662
                'uk_pt' => 8.32856176149081E-01,
663
                'qt' => 5.00000000000000E-01,
664
                'gal' => 1.25000000000000E-01,
665
                'l' => 4.73279432064682E-01,
666
                'lt' => 4.73279432064682E-01,
667
            ],
668
            'uk_pt' => [
669
                'tsp' => 1.15266000000000E+02,
670
                'tbs' => 3.84220000000000E+01,
671
                'oz' => 1.92110000000000E+01,
672
                'cup' => 2.40137500000000E+00,
673
                'pt' => 1.20068750000000E+00,
674
                'us_pt' => 1.20068750000000E+00,
675
                'uk_pt' => 1.0,
676
                'qt' => 6.00343750000000E-01,
677
                'gal' => 1.50085937500000E-01,
678
                'l' => 5.68260698087162E-01,
679
                'lt' => 5.68260698087162E-01,
680
            ],
681
            'qt' => [
682
                'tsp' => 1.92000000000000E+02,
683
                'tbs' => 6.40000000000000E+01,
684
                'oz' => 3.20000000000000E+01,
685
                'cup' => 4.00000000000000E+00,
686
                'pt' => 2.00000000000000E+00,
687
                'us_pt' => 2.00000000000000E+00,
688
                'uk_pt' => 1.66571235229816E+00,
689
                'qt' => 1.0,
690
                'gal' => 2.50000000000000E-01,
691
                'l' => 9.46558864129363E-01,
692
                'lt' => 9.46558864129363E-01,
693
            ],
694
            'gal' => [
695
                'tsp' => 7.68000000000000E+02,
696
                'tbs' => 2.56000000000000E+02,
697
                'oz' => 1.28000000000000E+02,
698
                'cup' => 1.60000000000000E+01,
699
                'pt' => 8.00000000000000E+00,
700
                'us_pt' => 8.00000000000000E+00,
701
                'uk_pt' => 6.66284940919265E+00,
702
                'qt' => 4.00000000000000E+00,
703
                'gal' => 1.0,
704
                'l' => 3.78623545651745E+00,
705
                'lt' => 3.78623545651745E+00,
706
            ],
707
            'l' => [
708
                'tsp' => 2.02840000000000E+02,
709
                'tbs' => 6.76133333333333E+01,
710
                'oz' => 3.38066666666667E+01,
711
                'cup' => 4.22583333333333E+00,
712
                'pt' => 2.11291666666667E+00,
713
                'us_pt' => 2.11291666666667E+00,
714
                'uk_pt' => 1.75975569552166E+00,
715
                'qt' => 1.05645833333333E+00,
716
                'gal' => 2.64114583333333E-01,
717
                'l' => 1.0,
718
                'lt' => 1.0,
719
            ],
720
            'lt' => [
721
                'tsp' => 2.02840000000000E+02,
722
                'tbs' => 6.76133333333333E+01,
723
                'oz' => 3.38066666666667E+01,
724
                'cup' => 4.22583333333333E+00,
725
                'pt' => 2.11291666666667E+00,
726
                'us_pt' => 2.11291666666667E+00,
727
                'uk_pt' => 1.75975569552166E+00,
728
                'qt' => 1.05645833333333E+00,
729
                'gal' => 2.64114583333333E-01,
730
                'l' => 1.0,
731
                'lt' => 1.0,
732
            ],
733
        ],
734
    ];
735
736
    /**
737
     * parseComplex.
738
     *
739
     * Parses a complex number into its real and imaginary parts, and an I or J suffix
740
     *
741
     * @param    string $complexNumber The complex number
742
     *
743
     * @return    string[]    Indexed on "real", "imaginary" and "suffix"
744
     */
745 354
    public static function parseComplex($complexNumber)
746
    {
747 354
        $workString = (string) $complexNumber;
748
749 354
        $realNumber = $imaginary = 0;
0 ignored issues
show
Unused Code introduced by
$realNumber is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
750
        //    Extract the suffix, if there is one
751 354
        $suffix = substr($workString, -1);
752 354
        if (!is_numeric($suffix)) {
753 289
            $workString = substr($workString, 0, -1);
754
        } else {
755 142
            $suffix = '';
756
        }
757
758
        //    Split the input into its Real and Imaginary components
759 354
        $leadingSign = 0;
760 354
        if (strlen($workString) > 0) {
761 345
            $leadingSign = (($workString[0] == '+') || ($workString[0] == '-')) ? 1 : 0;
762
        }
763 354
        $power = '';
764 354
        $realNumber = strtok($workString, '+-');
765 354
        if (strtoupper(substr($realNumber, -1)) == 'E') {
766 8
            $power = strtok('+-');
767 8
            ++$leadingSign;
768
        }
769
770 354
        $realNumber = substr($workString, 0, strlen($realNumber) + strlen($power) + $leadingSign);
771
772 354
        if ($suffix != '') {
773 289
            $imaginary = substr($workString, strlen($realNumber));
774
775 289
            if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) {
776 24
                $imaginary = $realNumber . '1';
777 24
                $realNumber = '0';
778 269
            } elseif ($imaginary == '') {
779 30
                $imaginary = $realNumber;
780 30
                $realNumber = '0';
781 243
            } elseif (($imaginary == '+') || ($imaginary == '-')) {
782 96
                $imaginary .= '1';
783
            }
784
        }
785
786
        return [
787 354
            'real' => $realNumber,
788 354
            'imaginary' => $imaginary,
789 354
            'suffix' => $suffix,
790
        ];
791
    }
792
793
    /**
794
     * Cleans the leading characters in a complex number string.
795
     *
796
     * @param    string $complexNumber The complex number to clean
797
     *
798
     * @return    string        The "cleaned" complex number
799
     */
800 38
    private static function cleanComplex($complexNumber)
801
    {
802 38
        if ($complexNumber[0] == '+') {
803
            $complexNumber = substr($complexNumber, 1);
804
        }
805 38
        if ($complexNumber[0] == '0') {
806 4
            $complexNumber = substr($complexNumber, 1);
807
        }
808 38
        if ($complexNumber[0] == '.') {
809 4
            $complexNumber = '0' . $complexNumber;
810
        }
811 38
        if ($complexNumber[0] == '+') {
812
            $complexNumber = substr($complexNumber, 1);
813
        }
814
815 38
        return $complexNumber;
816
    }
817
818
    /**
819
     * Formats a number base string value with leading zeroes.
820
     *
821
     * @param    string $xVal The "number" to pad
822
     * @param    int $places The length that we want to pad this value
823
     *
824
     * @return    string        The padded "number"
825
     */
826 82
    private static function nbrConversionFormat($xVal, $places)
827
    {
828 82
        if (!is_null($places)) {
829 22
            if (is_numeric($places)) {
830 18
                $places = (int) $places;
831
            } else {
832 4
                return Functions::VALUE();
833
            }
834 18
            if ($places < 0) {
835 4
                return Functions::NAN();
836
            }
837 14
            if (strlen($xVal) <= $places) {
838 14
                return substr(str_pad($xVal, $places, '0', STR_PAD_LEFT), -10);
839
            }
840
841
            return Functions::NAN();
842
        }
843
844 60
        return substr($xVal, -10);
845
    }
846
847
    /**
848
     *    BESSELI.
849
     *
850
     *    Returns the modified Bessel function In(x), which is equivalent to the Bessel function evaluated
851
     *        for purely imaginary arguments
852
     *
853
     *    Excel Function:
854
     *        BESSELI(x,ord)
855
     *
856
     * @category Engineering Functions
857
     *
858
     * @param    float $x The value at which to evaluate the function.
859
     *                                If x is nonnumeric, BESSELI returns the #VALUE! error value.
860
     * @param    int $ord The order of the Bessel function.
861
     *                                If ord is not an integer, it is truncated.
862
     *                                If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
863
     *                                If $ord < 0, BESSELI returns the #NUM! error value.
864
     *
865
     * @return    float
866
     */
867 74
    public static function BESSELI($x, $ord)
868
    {
869 74
        $x = (is_null($x)) ? 0.0 : Functions::flattenSingleValue($x);
870 74
        $ord = (is_null($ord)) ? 0.0 : Functions::flattenSingleValue($ord);
871
872 74
        if ((is_numeric($x)) && (is_numeric($ord))) {
873 70
            $ord = floor($ord);
874 70
            if ($ord < 0) {
875 2
                return Functions::NAN();
876
            }
877
878 68
            if (abs($x) <= 30) {
879 68
                $fResult = $fTerm = pow($x / 2, $ord) / MathTrig::FACT($ord);
880 68
                $ordK = 1;
881 68
                $fSqrX = ($x * $x) / 4;
882 View Code Duplication
                do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
883 68
                    $fTerm *= $fSqrX;
884 68
                    $fTerm /= ($ordK * ($ordK + $ord));
885 68
                    $fResult += $fTerm;
886 68
                } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
887
            } else {
888
                $f_2_PI = 2 * M_PI;
889
890
                $fXAbs = abs($x);
891
                $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
892
                if (($ord & 1) && ($x < 0)) {
893
                    $fResult = -$fResult;
894
                }
895
            }
896
897 68
            return (is_nan($fResult)) ? Functions::NAN() : $fResult;
898
        }
899
900 4
        return Functions::VALUE();
901
    }
902
903
    /**
904
     *    BESSELJ.
905
     *
906
     *    Returns the Bessel function
907
     *
908
     *    Excel Function:
909
     *        BESSELJ(x,ord)
910
     *
911
     * @category Engineering Functions
912
     *
913
     * @param    float $x The value at which to evaluate the function.
914
     *                                If x is nonnumeric, BESSELJ returns the #VALUE! error value.
915
     * @param    int $ord The order of the Bessel function. If n is not an integer, it is truncated.
916
     *                                If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
917
     *                                If $ord < 0, BESSELJ returns the #NUM! error value.
918
     *
919
     * @return    float
920
     */
921 50
    public static function BESSELJ($x, $ord)
922
    {
923 50
        $x = (is_null($x)) ? 0.0 : Functions::flattenSingleValue($x);
924 50
        $ord = (is_null($ord)) ? 0.0 : Functions::flattenSingleValue($ord);
925
926 50
        if ((is_numeric($x)) && (is_numeric($ord))) {
927 48
            $ord = floor($ord);
928 48
            if ($ord < 0) {
929 1
                return Functions::NAN();
930
            }
931
932 47
            $fResult = 0;
0 ignored issues
show
Unused Code introduced by
$fResult is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
933 47
            if (abs($x) <= 30) {
934 47
                $fResult = $fTerm = pow($x / 2, $ord) / MathTrig::FACT($ord);
935 47
                $ordK = 1;
936 47
                $fSqrX = ($x * $x) / -4;
937 View Code Duplication
                do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
938 47
                    $fTerm *= $fSqrX;
939 47
                    $fTerm /= ($ordK * ($ordK + $ord));
940 47
                    $fResult += $fTerm;
941 47
                } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
942
            } else {
943
                $f_PI_DIV_2 = M_PI / 2;
944
                $f_PI_DIV_4 = M_PI / 4;
945
946
                $fXAbs = abs($x);
947
                $fResult = sqrt(M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4);
948
                if (($ord & 1) && ($x < 0)) {
949
                    $fResult = -$fResult;
950
                }
951
            }
952
953 47
            return (is_nan($fResult)) ? Functions::NAN() : $fResult;
954
        }
955
956 2
        return Functions::VALUE();
957
    }
958
959 22
    private static function besselK0($fNum)
960
    {
961 22
        if ($fNum <= 2) {
962 14
            $fNum2 = $fNum * 0.5;
963 14
            $y = ($fNum2 * $fNum2);
964 14
            $fRet = -log($fNum2) * self::BESSELI($fNum, 0) +
965
                (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
966 14
                                    (0.10750e-3 + $y * 0.74e-5))))));
967 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
968 8
            $y = 2 / $fNum;
969 8
            $fRet = exp(-$fNum) / sqrt($fNum) *
970
                (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
971 8
                                (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
972
        }
973
974 22
        return $fRet;
975
    }
976
977 30
    private static function besselK1($fNum)
978
    {
979 30
        if ($fNum <= 2) {
980 17
            $fNum2 = $fNum * 0.5;
981 17
            $y = ($fNum2 * $fNum2);
982 17
            $fRet = log($fNum2) * self::BESSELI($fNum, 1) +
983
                (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
984 17
                                    (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
985 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
986 13
            $y = 2 / $fNum;
987 13
            $fRet = exp(-$fNum) / sqrt($fNum) *
988
                (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
989 13
                                    (0.325614e-2 + $y * (-0.68245e-3)))))));
990
        }
991
992 30
        return $fRet;
993
    }
994
995
    /**
996
     *    BESSELK.
997
     *
998
     *    Returns the modified Bessel function Kn(x), which is equivalent to the Bessel functions evaluated
999
     *        for purely imaginary arguments.
1000
     *
1001
     *    Excel Function:
1002
     *        BESSELK(x,ord)
1003
     *
1004
     * @category Engineering Functions
1005
     *
1006
     * @param    float $x The value at which to evaluate the function.
1007
     *                                If x is nonnumeric, BESSELK returns the #VALUE! error value.
1008
     * @param    int $ord The order of the Bessel function. If n is not an integer, it is truncated.
1009
     *                                If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
1010
     *                                If $ord < 0, BESSELK returns the #NUM! error value.
1011
     *
1012
     * @return    float
1013
     */
1014 38 View Code Duplication
    public static function BESSELK($x, $ord)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1015
    {
1016 38
        $x = (is_null($x)) ? 0.0 : Functions::flattenSingleValue($x);
1017 38
        $ord = (is_null($ord)) ? 0.0 : Functions::flattenSingleValue($ord);
1018
1019 38
        if ((is_numeric($x)) && (is_numeric($ord))) {
1020 36
            if (($ord < 0) || ($x == 0.0)) {
1021 4
                return Functions::NAN();
1022
            }
1023
1024 32
            switch (floor($ord)) {
1025 32
                case 0:
1026 2
                    $fBk = self::besselK0($x);
1027 2
                    break;
1028 30
                case 1:
1029 10
                    $fBk = self::besselK1($x);
1030 10
                    break;
1031
                default:
1032 20
                    $fTox = 2 / $x;
1033 20
                    $fBkm = self::besselK0($x);
1034 20
                    $fBk = self::besselK1($x);
1035 20
                    for ($n = 1; $n < $ord; ++$n) {
1036 20
                        $fBkp = $fBkm + $n * $fTox * $fBk;
1037 20
                        $fBkm = $fBk;
1038 20
                        $fBk = $fBkp;
1039
                    }
1040
            }
1041
1042 32
            return (is_nan($fBk)) ? Functions::NAN() : $fBk;
1043
        }
1044
1045 2
        return Functions::VALUE();
1046
    }
1047
1048 11
    private static function besselY0($fNum)
1049
    {
1050 11
        if ($fNum < 8.0) {
1051 10
            $y = ($fNum * $fNum);
1052 10
            $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733))));
1053 10
            $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y))));
1054 10
            $fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum);
1055
        } else {
1056 1
            $z = 8.0 / $fNum;
1057 1
            $y = ($z * $z);
1058 1
            $xx = $fNum - 0.785398164;
1059 1
            $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
1060 1
            $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7))));
1061 1
            $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
1062
        }
1063
1064 11
        return $fRet;
1065
    }
1066
1067 16
    private static function besselY1($fNum)
1068
    {
1069 16
        if ($fNum < 8.0) {
1070 16
            $y = ($fNum * $fNum);
1071
            $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y *
1072 16
                                (-0.4237922726e7 + $y * 0.8511937935e4)))));
1073
            $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
1074 16
                            (0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
1075 16
            $fRet = $f1 / $f2 + 0.636619772 * (self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
1076
        } else {
1077
            $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
1078
        }
1079
1080 16
        return $fRet;
1081
    }
1082
1083
    /**
1084
     *    BESSELY.
1085
     *
1086
     *    Returns the Bessel function, which is also called the Weber function or the Neumann function.
1087
     *
1088
     *    Excel Function:
1089
     *        BESSELY(x,ord)
1090
     *
1091
     * @category Engineering Functions
1092
     *
1093
     * @param    float $x The value at which to evaluate the function.
1094
     *                                If x is nonnumeric, BESSELK returns the #VALUE! error value.
1095
     * @param    int $ord The order of the Bessel function. If n is not an integer, it is truncated.
1096
     *                                If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
1097
     *                                If $ord < 0, BESSELK returns the #NUM! error value.
1098
     *
1099
     * @return    float
1100
     */
1101 23 View Code Duplication
    public static function BESSELY($x, $ord)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1102
    {
1103 23
        $x = (is_null($x)) ? 0.0 : Functions::flattenSingleValue($x);
1104 23
        $ord = (is_null($ord)) ? 0.0 : Functions::flattenSingleValue($ord);
1105
1106 23
        if ((is_numeric($x)) && (is_numeric($ord))) {
1107 21
            if (($ord < 0) || ($x == 0.0)) {
1108 3
                return Functions::NAN();
1109
            }
1110
1111 18
            switch (floor($ord)) {
1112 18
                case 0:
1113 2
                    $fBy = self::besselY0($x);
1114 2
                    break;
1115 16
                case 1:
1116 7
                    $fBy = self::besselY1($x);
1117 7
                    break;
1118
                default:
1119 9
                    $fTox = 2 / $x;
1120 9
                    $fBym = self::besselY0($x);
1121 9
                    $fBy = self::besselY1($x);
1122 9
                    for ($n = 1; $n < $ord; ++$n) {
1123 9
                        $fByp = $n * $fTox * $fBy - $fBym;
1124 9
                        $fBym = $fBy;
1125 9
                        $fBy = $fByp;
1126
                    }
1127
            }
1128
1129 18
            return (is_nan($fBy)) ? Functions::NAN() : $fBy;
1130
        }
1131
1132 2
        return Functions::VALUE();
1133
    }
1134
1135
    /**
1136
     * BINTODEC.
1137
     *
1138
     * Return a binary value as decimal.
1139
     *
1140
     * Excel Function:
1141
     *        BIN2DEC(x)
1142
     *
1143
     * @category Engineering Functions
1144
     *
1145
     * @param    string $x The binary number (as a string) that you want to convert. The number
1146
     *                                cannot contain more than 10 characters (10 bits). The most significant
1147
     *                                bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1148
     *                                Negative numbers are represented using two's-complement notation.
1149
     *                                If number is not a valid binary number, or if number contains more than
1150
     *                                10 characters (10 bits), BIN2DEC returns the #NUM! error value.
1151
     *
1152
     * @return    string
1153
     */
1154 10
    public static function BINTODEC($x)
1155
    {
1156 10
        $x = Functions::flattenSingleValue($x);
1157
1158 10
        if (is_bool($x)) {
1159 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1160
                $x = (int) $x;
1161
            } else {
1162 1
                return Functions::VALUE();
1163
            }
1164
        }
1165 9
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1166
            $x = floor($x);
1167
        }
1168 9
        $x = (string) $x;
1169 9
        if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1170 1
            return Functions::NAN();
1171
        }
1172 8
        if (strlen($x) > 10) {
1173 1
            return Functions::NAN();
1174 7
        } elseif (strlen($x) == 10) {
1175
            //    Two's Complement
1176 2
            $x = substr($x, -9);
1177
1178 2
            return '-' . (512 - bindec($x));
1179
        }
1180
1181 5
        return bindec($x);
1182
    }
1183
1184
    /**
1185
     * BINTOHEX.
1186
     *
1187
     * Return a binary value as hex.
1188
     *
1189
     * Excel Function:
1190
     *        BIN2HEX(x[,places])
1191
     *
1192
     * @category Engineering Functions
1193
     *
1194
     * @param    string $x The binary number (as a string) that you want to convert. The number
1195
     *                                cannot contain more than 10 characters (10 bits). The most significant
1196
     *                                bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1197
     *                                Negative numbers are represented using two's-complement notation.
1198
     *                                If number is not a valid binary number, or if number contains more than
1199
     *                                10 characters (10 bits), BIN2HEX returns the #NUM! error value.
1200
     * @param    int $places The number of characters to use. If places is omitted, BIN2HEX uses the
1201
     *                                minimum number of characters necessary. Places is useful for padding the
1202
     *                                return value with leading 0s (zeros).
1203
     *                                If places is not an integer, it is truncated.
1204
     *                                If places is nonnumeric, BIN2HEX returns the #VALUE! error value.
1205
     *                                If places is negative, BIN2HEX returns the #NUM! error value.
1206
     *
1207
     * @return    string
1208
     */
1209 14 View Code Duplication
    public static function BINTOHEX($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1210
    {
1211 14
        $x = Functions::flattenSingleValue($x);
1212 14
        $places = Functions::flattenSingleValue($places);
1213
1214
        // Argument X
1215 14
        if (is_bool($x)) {
1216 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1217
                $x = (int) $x;
1218
            } else {
1219 1
                return Functions::VALUE();
1220
            }
1221
        }
1222 13
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1223
            $x = floor($x);
1224
        }
1225 13
        $x = (string) $x;
1226 13
        if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1227 1
            return Functions::NAN();
1228
        }
1229 12
        if (strlen($x) > 10) {
1230 1
            return Functions::NAN();
1231 11
        } elseif (strlen($x) == 10) {
1232
            //    Two's Complement
1233 2
            return str_repeat('F', 8) . substr(strtoupper(dechex(bindec(substr($x, -9)))), -2);
1234
        }
1235 9
        $hexVal = (string) strtoupper(dechex(bindec($x)));
1236
1237 9
        return self::nbrConversionFormat($hexVal, $places);
1238
    }
1239
1240
    /**
1241
     * BINTOOCT.
1242
     *
1243
     * Return a binary value as octal.
1244
     *
1245
     * Excel Function:
1246
     *        BIN2OCT(x[,places])
1247
     *
1248
     * @category Engineering Functions
1249
     *
1250
     * @param    string $x The binary number (as a string) that you want to convert. The number
1251
     *                                cannot contain more than 10 characters (10 bits). The most significant
1252
     *                                bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1253
     *                                Negative numbers are represented using two's-complement notation.
1254
     *                                If number is not a valid binary number, or if number contains more than
1255
     *                                10 characters (10 bits), BIN2OCT returns the #NUM! error value.
1256
     * @param    int $places The number of characters to use. If places is omitted, BIN2OCT uses the
1257
     *                                minimum number of characters necessary. Places is useful for padding the
1258
     *                                return value with leading 0s (zeros).
1259
     *                                If places is not an integer, it is truncated.
1260
     *                                If places is nonnumeric, BIN2OCT returns the #VALUE! error value.
1261
     *                                If places is negative, BIN2OCT returns the #NUM! error value.
1262
     *
1263
     * @return    string
1264
     */
1265 15 View Code Duplication
    public static function BINTOOCT($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1266
    {
1267 15
        $x = Functions::flattenSingleValue($x);
1268 15
        $places = Functions::flattenSingleValue($places);
1269
1270 15
        if (is_bool($x)) {
1271 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1272
                $x = (int) $x;
1273
            } else {
1274 1
                return Functions::VALUE();
1275
            }
1276
        }
1277 14
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1278
            $x = floor($x);
1279
        }
1280 14
        $x = (string) $x;
1281 14
        if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1282 1
            return Functions::NAN();
1283
        }
1284 13
        if (strlen($x) > 10) {
1285 1
            return Functions::NAN();
1286 12
        } elseif (strlen($x) == 10) {
1287
            //    Two's Complement
1288 2
            return str_repeat('7', 7) . substr(strtoupper(decoct(bindec(substr($x, -9)))), -3);
1289
        }
1290 10
        $octVal = (string) decoct(bindec($x));
1291
1292 10
        return self::nbrConversionFormat($octVal, $places);
1293
    }
1294
1295
    /**
1296
     * DECTOBIN.
1297
     *
1298
     * Return a decimal value as binary.
1299
     *
1300
     * Excel Function:
1301
     *        DEC2BIN(x[,places])
1302
     *
1303
     * @category Engineering Functions
1304
     *
1305
     * @param    string $x The decimal integer you want to convert. If number is negative,
1306
     *                                valid place values are ignored and DEC2BIN returns a 10-character
1307
     *                                (10-bit) binary number in which the most significant bit is the sign
1308
     *                                bit. The remaining 9 bits are magnitude bits. Negative numbers are
1309
     *                                represented using two's-complement notation.
1310
     *                                If number < -512 or if number > 511, DEC2BIN returns the #NUM! error
1311
     *                                value.
1312
     *                                If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
1313
     *                                If DEC2BIN requires more than places characters, it returns the #NUM!
1314
     *                                error value.
1315
     * @param    int $places The number of characters to use. If places is omitted, DEC2BIN uses
1316
     *                                the minimum number of characters necessary. Places is useful for
1317
     *                                padding the return value with leading 0s (zeros).
1318
     *                                If places is not an integer, it is truncated.
1319
     *                                If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
1320
     *                                If places is zero or negative, DEC2BIN returns the #NUM! error value.
1321
     *
1322
     * @return    string
1323
     */
1324 41
    public static function DECTOBIN($x, $places = null)
1325
    {
1326 41
        $x = Functions::flattenSingleValue($x);
1327 41
        $places = Functions::flattenSingleValue($places);
1328
1329 41
        if (is_bool($x)) {
1330 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1331
                $x = (int) $x;
1332
            } else {
1333 1
                return Functions::VALUE();
1334
            }
1335
        }
1336 40
        $x = (string) $x;
1337 40
        if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1338 1
            return Functions::VALUE();
1339
        }
1340
1341 39
        $x = (string) floor($x);
1342 39
        if ($x < -512 || $x > 511) {
1343 13
            return Functions::NAN();
1344
        }
1345
1346 26
        $r = decbin($x);
1347
        // Two's Complement
1348 26
        $r = substr($r, -10);
1349 26
        if (strlen($r) >= 11) {
1350
            return Functions::NAN();
1351
        }
1352
1353 26
        return self::nbrConversionFormat($r, $places);
1354
    }
1355
1356
    /**
1357
     * DECTOHEX.
1358
     *
1359
     * Return a decimal value as hex.
1360
     *
1361
     * Excel Function:
1362
     *        DEC2HEX(x[,places])
1363
     *
1364
     * @category Engineering Functions
1365
     *
1366
     * @param    string $x The decimal integer you want to convert. If number is negative,
1367
     *                                places is ignored and DEC2HEX returns a 10-character (40-bit)
1368
     *                                hexadecimal number in which the most significant bit is the sign
1369
     *                                bit. The remaining 39 bits are magnitude bits. Negative numbers
1370
     *                                are represented using two's-complement notation.
1371
     *                                If number < -549,755,813,888 or if number > 549,755,813,887,
1372
     *                                DEC2HEX returns the #NUM! error value.
1373
     *                                If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
1374
     *                                If DEC2HEX requires more than places characters, it returns the
1375
     *                                #NUM! error value.
1376
     * @param    int $places The number of characters to use. If places is omitted, DEC2HEX uses
1377
     *                                the minimum number of characters necessary. Places is useful for
1378
     *                                padding the return value with leading 0s (zeros).
1379
     *                                If places is not an integer, it is truncated.
1380
     *                                If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
1381
     *                                If places is zero or negative, DEC2HEX returns the #NUM! error value.
1382
     *
1383
     * @return    string
1384
     */
1385 15 View Code Duplication
    public static function DECTOHEX($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1386
    {
1387 15
        $x = Functions::flattenSingleValue($x);
1388 15
        $places = Functions::flattenSingleValue($places);
1389
1390 15
        if (is_bool($x)) {
1391 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1392
                $x = (int) $x;
1393
            } else {
1394 1
                return Functions::VALUE();
1395
            }
1396
        }
1397 14
        $x = (string) $x;
1398 14
        if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1399 1
            return Functions::VALUE();
1400
        }
1401 13
        $x = (string) floor($x);
1402 13
        $r = strtoupper(dechex($x));
1403 13
        if (strlen($r) == 8) {
1404
            //    Two's Complement
1405
            $r = 'FF' . $r;
1406
        }
1407
1408 13
        return self::nbrConversionFormat($r, $places);
1409
    }
1410
1411
    /**
1412
     * DECTOOCT.
1413
     *
1414
     * Return an decimal value as octal.
1415
     *
1416
     * Excel Function:
1417
     *        DEC2OCT(x[,places])
1418
     *
1419
     * @category Engineering Functions
1420
     *
1421
     * @param    string $x The decimal integer you want to convert. If number is negative,
1422
     *                                places is ignored and DEC2OCT returns a 10-character (30-bit)
1423
     *                                octal number in which the most significant bit is the sign bit.
1424
     *                                The remaining 29 bits are magnitude bits. Negative numbers are
1425
     *                                represented using two's-complement notation.
1426
     *                                If number < -536,870,912 or if number > 536,870,911, DEC2OCT
1427
     *                                returns the #NUM! error value.
1428
     *                                If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
1429
     *                                If DEC2OCT requires more than places characters, it returns the
1430
     *                                #NUM! error value.
1431
     * @param    int $places The number of characters to use. If places is omitted, DEC2OCT uses
1432
     *                                the minimum number of characters necessary. Places is useful for
1433
     *                                padding the return value with leading 0s (zeros).
1434
     *                                If places is not an integer, it is truncated.
1435
     *                                If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
1436
     *                                If places is zero or negative, DEC2OCT returns the #NUM! error value.
1437
     *
1438
     * @return    string
1439
     */
1440 20 View Code Duplication
    public static function DECTOOCT($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1441
    {
1442 20
        $xorig = $x;
0 ignored issues
show
Unused Code introduced by
$xorig is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1443 20
        $x = Functions::flattenSingleValue($x);
1444 20
        $places = Functions::flattenSingleValue($places);
1445
1446 20
        if (is_bool($x)) {
1447 1
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1448
                $x = (int) $x;
1449
            } else {
1450 1
                return Functions::VALUE();
1451
            }
1452
        }
1453 19
        $x = (string) $x;
1454 19
        if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1455 1
            return Functions::VALUE();
1456
        }
1457 18
        $x = (string) floor($x);
1458 18
        $r = decoct($x);
1459 18
        if (strlen($r) == 11) {
1460
            //    Two's Complement
1461
            $r = substr($r, -10);
1462
        }
1463
1464 18
        return self::nbrConversionFormat($r, $places);
1465
    }
1466
1467
    /**
1468
     * HEXTOBIN.
1469
     *
1470
     * Return a hex value as binary.
1471
     *
1472
     * Excel Function:
1473
     *        HEX2BIN(x[,places])
1474
     *
1475
     * @category Engineering Functions
1476
     *
1477
     * @param    string $x the hexadecimal number you want to convert.
1478
     *                  Number cannot contain more than 10 characters.
1479
     *                  The most significant bit of number is the sign bit (40th bit from the right).
1480
     *                  The remaining 9 bits are magnitude bits.
1481
     *                  Negative numbers are represented using two's-complement notation.
1482
     *                  If number is negative, HEX2BIN ignores places and returns a 10-character binary number.
1483
     *                  If number is negative, it cannot be less than FFFFFFFE00,
1484
     *                      and if number is positive, it cannot be greater than 1FF.
1485
     *                  If number is not a valid hexadecimal number, HEX2BIN returns the #NUM! error value.
1486
     *                  If HEX2BIN requires more than places characters, it returns the #NUM! error value.
1487
     * @param    int $places The number of characters to use. If places is omitted,
1488
     *                                    HEX2BIN uses the minimum number of characters necessary. Places
1489
     *                                    is useful for padding the return value with leading 0s (zeros).
1490
     *                                    If places is not an integer, it is truncated.
1491
     *                                    If places is nonnumeric, HEX2BIN returns the #VALUE! error value.
1492
     *                                    If places is negative, HEX2BIN returns the #NUM! error value.
1493
     *
1494
     * @return    string
1495
     */
1496 16 View Code Duplication
    public static function HEXTOBIN($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1497
    {
1498 16
        $x = Functions::flattenSingleValue($x);
1499 16
        $places = Functions::flattenSingleValue($places);
1500
1501 16
        if (is_bool($x)) {
1502 1
            return Functions::VALUE();
1503
        }
1504 15
        $x = (string) $x;
1505 15
        if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1506 2
            return Functions::NAN();
1507
        }
1508
1509 13
        return self::DECTOBIN(self::HEXTODEC($x), $places);
1510
    }
1511
1512
    /**
1513
     * HEXTODEC.
1514
     *
1515
     * Return a hex value as decimal.
1516
     *
1517
     * Excel Function:
1518
     *        HEX2DEC(x)
1519
     *
1520
     * @category Engineering Functions
1521
     *
1522
     * @param    string $x The hexadecimal number you want to convert. This number cannot
1523
     *                                contain more than 10 characters (40 bits). The most significant
1524
     *                                bit of number is the sign bit. The remaining 39 bits are magnitude
1525
     *                                bits. Negative numbers are represented using two's-complement
1526
     *                                notation.
1527
     *                                If number is not a valid hexadecimal number, HEX2DEC returns the
1528
     *                                #NUM! error value.
1529
     *
1530
     * @return    string
1531
     */
1532 37
    public static function HEXTODEC($x)
1533
    {
1534 37
        $x = Functions::flattenSingleValue($x);
1535
1536 37
        if (is_bool($x)) {
1537 1
            return Functions::VALUE();
1538
        }
1539 36
        $x = (string) $x;
1540 36
        if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1541 3
            return Functions::NAN();
1542
        }
1543
1544 33
        if (strlen($x) > 10) {
1545 1
            return Functions::NAN();
1546
        }
1547
1548 32
        $binX = '';
1549 32 View Code Duplication
        foreach (str_split($x) as $char) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1550 32
            $binX .= str_pad(base_convert($char, 16, 2), 4, '0', STR_PAD_LEFT);
1551
        }
1552 32 View Code Duplication
        if (strlen($binX) == 40 && $binX[0] == '1') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1553 5
            for ($i = 0; $i < 40; ++$i) {
1554 5
                $binX[$i] = ($binX[$i] == '1' ? '0' : '1');
1555
            }
1556
1557 5
            return (bindec($binX) + 1) * -1;
1558
        }
1559
1560 27
        return bindec($binX);
1561
    }
1562
1563
    /**
1564
     * HEXTOOCT.
1565
     *
1566
     * Return a hex value as octal.
1567
     *
1568
     * Excel Function:
1569
     *        HEX2OCT(x[,places])
1570
     *
1571
     * @category Engineering Functions
1572
     *
1573
     * @param    string $x The hexadecimal number you want to convert. Number cannot
1574
     *                                    contain more than 10 characters. The most significant bit of
1575
     *                                    number is the sign bit. The remaining 39 bits are magnitude
1576
     *                                    bits. Negative numbers are represented using two's-complement
1577
     *                                    notation.
1578
     *                                    If number is negative, HEX2OCT ignores places and returns a
1579
     *                                    10-character octal number.
1580
     *                                    If number is negative, it cannot be less than FFE0000000, and
1581
     *                                    if number is positive, it cannot be greater than 1FFFFFFF.
1582
     *                                    If number is not a valid hexadecimal number, HEX2OCT returns
1583
     *                                    the #NUM! error value.
1584
     *                                    If HEX2OCT requires more than places characters, it returns
1585
     *                                    the #NUM! error value.
1586
     * @param    int $places The number of characters to use. If places is omitted, HEX2OCT
1587
     *                                    uses the minimum number of characters necessary. Places is
1588
     *                                    useful for padding the return value with leading 0s (zeros).
1589
     *                                    If places is not an integer, it is truncated.
1590
     *                                    If places is nonnumeric, HEX2OCT returns the #VALUE! error
1591
     *                                    value.
1592
     *                                    If places is negative, HEX2OCT returns the #NUM! error value.
1593
     *
1594
     * @return    string
1595
     */
1596 13
    public static function HEXTOOCT($x, $places = null)
1597
    {
1598 13
        $x = Functions::flattenSingleValue($x);
1599 13
        $places = Functions::flattenSingleValue($places);
1600
1601 13
        if (is_bool($x)) {
1602 1
            return Functions::VALUE();
1603
        }
1604 12
        $x = (string) $x;
1605 12
        if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1606 3
            return Functions::NAN();
1607
        }
1608
1609 9
        $decimal = self::HEXTODEC($x);
1610 9
        if ($decimal < -536870912 || $decimal > 536870911) {
1611 1
            return Functions::NAN();
1612
        }
1613
1614 8
        return self::DECTOOCT($decimal, $places);
1615
    }
1616
1617
    /**
1618
     * OCTTOBIN.
1619
     *
1620
     * Return an octal value as binary.
1621
     *
1622
     * Excel Function:
1623
     *        OCT2BIN(x[,places])
1624
     *
1625
     * @category Engineering Functions
1626
     *
1627
     * @param    string $x The octal number you want to convert. Number may not
1628
     *                                    contain more than 10 characters. The most significant
1629
     *                                    bit of number is the sign bit. The remaining 29 bits
1630
     *                                    are magnitude bits. Negative numbers are represented
1631
     *                                    using two's-complement notation.
1632
     *                                    If number is negative, OCT2BIN ignores places and returns
1633
     *                                    a 10-character binary number.
1634
     *                                    If number is negative, it cannot be less than 7777777000,
1635
     *                                    and if number is positive, it cannot be greater than 777.
1636
     *                                    If number is not a valid octal number, OCT2BIN returns
1637
     *                                    the #NUM! error value.
1638
     *                                    If OCT2BIN requires more than places characters, it
1639
     *                                    returns the #NUM! error value.
1640
     * @param    int $places The number of characters to use. If places is omitted,
1641
     *                                    OCT2BIN uses the minimum number of characters necessary.
1642
     *                                    Places is useful for padding the return value with
1643
     *                                    leading 0s (zeros).
1644
     *                                    If places is not an integer, it is truncated.
1645
     *                                    If places is nonnumeric, OCT2BIN returns the #VALUE!
1646
     *                                    error value.
1647
     *                                    If places is negative, OCT2BIN returns the #NUM! error
1648
     *                                    value.
1649
     *
1650
     * @return    string
1651
     */
1652 13 View Code Duplication
    public static function OCTTOBIN($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1653
    {
1654 13
        $x = Functions::flattenSingleValue($x);
1655 13
        $places = Functions::flattenSingleValue($places);
1656
1657 13
        if (is_bool($x)) {
1658 1
            return Functions::VALUE();
1659
        }
1660 12
        $x = (string) $x;
1661 12
        if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1662 2
            return Functions::NAN();
1663
        }
1664
1665 10
        return self::DECTOBIN(self::OCTTODEC($x), $places);
1666
    }
1667
1668
    /**
1669
     * OCTTODEC.
1670
     *
1671
     * Return an octal value as decimal.
1672
     *
1673
     * Excel Function:
1674
     *        OCT2DEC(x)
1675
     *
1676
     * @category Engineering Functions
1677
     *
1678
     * @param    string $x The octal number you want to convert. Number may not contain
1679
     *                                more than 10 octal characters (30 bits). The most significant
1680
     *                                bit of number is the sign bit. The remaining 29 bits are
1681
     *                                magnitude bits. Negative numbers are represented using
1682
     *                                two's-complement notation.
1683
     *                                If number is not a valid octal number, OCT2DEC returns the
1684
     *                                #NUM! error value.
1685
     *
1686
     * @return    string
1687
     */
1688 25
    public static function OCTTODEC($x)
1689
    {
1690 25
        $x = Functions::flattenSingleValue($x);
1691
1692 25
        if (is_bool($x)) {
1693 1
            return Functions::VALUE();
1694
        }
1695 24
        $x = (string) $x;
1696 24
        if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1697 2
            return Functions::NAN();
1698
        }
1699 22
        $binX = '';
1700 22 View Code Duplication
        foreach (str_split($x) as $char) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1701 22
            $binX .= str_pad(decbin((int) $char), 3, '0', STR_PAD_LEFT);
1702
        }
1703 22 View Code Duplication
        if (strlen($binX) == 30 && $binX[0] == '1') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1704 4
            for ($i = 0; $i < 30; ++$i) {
1705 4
                $binX[$i] = ($binX[$i] == '1' ? '0' : '1');
1706
            }
1707
1708 4
            return (bindec($binX) + 1) * -1;
1709
        }
1710
1711 18
        return bindec($binX);
1712
    }
1713
1714
    /**
1715
     * OCTTOHEX.
1716
     *
1717
     * Return an octal value as hex.
1718
     *
1719
     * Excel Function:
1720
     *        OCT2HEX(x[,places])
1721
     *
1722
     * @category Engineering Functions
1723
     *
1724
     * @param    string $x The octal number you want to convert. Number may not contain
1725
     *                                    more than 10 octal characters (30 bits). The most significant
1726
     *                                    bit of number is the sign bit. The remaining 29 bits are
1727
     *                                    magnitude bits. Negative numbers are represented using
1728
     *                                    two's-complement notation.
1729
     *                                    If number is negative, OCT2HEX ignores places and returns a
1730
     *                                    10-character hexadecimal number.
1731
     *                                    If number is not a valid octal number, OCT2HEX returns the
1732
     *                                    #NUM! error value.
1733
     *                                    If OCT2HEX requires more than places characters, it returns
1734
     *                                    the #NUM! error value.
1735
     * @param    int $places The number of characters to use. If places is omitted, OCT2HEX
1736
     *                                    uses the minimum number of characters necessary. Places is useful
1737
     *                                    for padding the return value with leading 0s (zeros).
1738
     *                                    If places is not an integer, it is truncated.
1739
     *                                    If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
1740
     *                                    If places is negative, OCT2HEX returns the #NUM! error value.
1741
     *
1742
     * @return    string
1743
     */
1744 9 View Code Duplication
    public static function OCTTOHEX($x, $places = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1745
    {
1746 9
        $x = Functions::flattenSingleValue($x);
1747 9
        $places = Functions::flattenSingleValue($places);
1748
1749 9
        if (is_bool($x)) {
1750 1
            return Functions::VALUE();
1751
        }
1752 8
        $x = (string) $x;
1753 8
        if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1754 2
            return Functions::NAN();
1755
        }
1756 6
        $hexVal = strtoupper(dechex(self::OCTTODEC($x)));
1757
1758 6
        return self::nbrConversionFormat($hexVal, $places);
1759
    }
1760
1761
    /**
1762
     * COMPLEX.
1763
     *
1764
     * Converts real and imaginary coefficients into a complex number of the form x + yi or x + yj.
1765
     *
1766
     * Excel Function:
1767
     *        COMPLEX(realNumber,imaginary[,places])
1768
     *
1769
     * @category Engineering Functions
1770
     *
1771
     * @param    float $realNumber the real coefficient of the complex number
1772
     * @param    float $imaginary the imaginary coefficient of the complex number
1773
     * @param    string $suffix The suffix for the imaginary component of the complex number.
1774
     *                                        If omitted, the suffix is assumed to be "i".
1775
     *
1776
     * @return    string
1777
     */
1778 759
    public static function COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i')
1779
    {
1780 759
        $realNumber = (is_null($realNumber)) ? 0.0 : Functions::flattenSingleValue($realNumber);
1781 759
        $imaginary = (is_null($imaginary)) ? 0.0 : Functions::flattenSingleValue($imaginary);
1782 759
        $suffix = (is_null($suffix)) ? 'i' : Functions::flattenSingleValue($suffix);
1783
1784 759
        if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
1785 759
            (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))
1786
        ) {
1787 758
            $realNumber = (float) $realNumber;
1788 758
            $imaginary = (float) $imaginary;
1789
1790 758
            if ($suffix == '') {
1791
                $suffix = 'i';
1792
            }
1793 758
            if ($realNumber == 0.0) {
1794 65
                if ($imaginary == 0.0) {
1795 6
                    return (string) '0';
1796 59
                } elseif ($imaginary == 1.0) {
1797 5
                    return (string) $suffix;
1798 54
                } elseif ($imaginary == -1.0) {
1799 2
                    return (string) '-' . $suffix;
1800
                }
1801
1802 52
                return (string) $imaginary . $suffix;
1803 693
            } elseif ($imaginary == 0.0) {
1804 54
                return (string) $realNumber;
1805 639
            } elseif ($imaginary == 1.0) {
1806 45
                return (string) $realNumber . '+' . $suffix;
1807 594
            } elseif ($imaginary == -1.0) {
1808 8
                return (string) $realNumber . '-' . $suffix;
1809
            }
1810 586
            if ($imaginary > 0) {
1811 329
                $imaginary = (string) '+' . $imaginary;
1812
            }
1813
1814 586
            return (string) $realNumber . $imaginary . $suffix;
1815
        }
1816
1817 1
        return Functions::VALUE();
1818
    }
1819
1820
    /**
1821
     * IMAGINARY.
1822
     *
1823
     * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
1824
     *
1825
     * Excel Function:
1826
     *        IMAGINARY(complexNumber)
1827
     *
1828
     * @category Engineering Functions
1829
     *
1830
     * @param    string $complexNumber the complex number for which you want the imaginary
1831
     *                                         coefficient
1832
     *
1833
     * @return    float
1834
     */
1835 30
    public static function IMAGINARY($complexNumber)
1836
    {
1837 30
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1838
1839 30
        $parsedComplex = self::parseComplex($complexNumber);
1840
1841 30
        return $parsedComplex['imaginary'];
1842
    }
1843
1844
    /**
1845
     * IMREAL.
1846
     *
1847
     * Returns the real coefficient of a complex number in x + yi or x + yj text format.
1848
     *
1849
     * Excel Function:
1850
     *        IMREAL(complexNumber)
1851
     *
1852
     * @category Engineering Functions
1853
     *
1854
     * @param    string $complexNumber the complex number for which you want the real coefficient
1855
     *
1856
     * @return    float
1857
     */
1858 30
    public static function IMREAL($complexNumber)
1859
    {
1860 30
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1861
1862 30
        $parsedComplex = self::parseComplex($complexNumber);
1863
1864 30
        return $parsedComplex['real'];
1865
    }
1866
1867
    /**
1868
     * IMABS.
1869
     *
1870
     * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
1871
     *
1872
     * Excel Function:
1873
     *        IMABS(complexNumber)
1874
     *
1875
     * @param    string $complexNumber the complex number for which you want the absolute value
1876
     *
1877
     * @return    float
1878
     */
1879 27
    public static function IMABS($complexNumber)
1880
    {
1881 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1882
1883 27
        $parsedComplex = self::parseComplex($complexNumber);
1884
1885 27
        return sqrt(
1886 27
            ($parsedComplex['real'] * $parsedComplex['real']) +
1887 27
            ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])
1888
        );
1889
    }
1890
1891
    /**
1892
     * IMARGUMENT.
1893
     *
1894
     * Returns the argument theta of a complex number, i.e. the angle in radians from the real
1895
     * axis to the representation of the number in polar coordinates.
1896
     *
1897
     * Excel Function:
1898
     *        IMARGUMENT(complexNumber)
1899
     *
1900
     * @param    string $complexNumber the complex number for which you want the argument theta
1901
     *
1902
     * @return    float
1903
     */
1904 128
    public static function IMARGUMENT($complexNumber)
1905
    {
1906 128
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1907 128
        $parsedComplex = self::parseComplex($complexNumber);
1908 128
        if ($parsedComplex['real'] == 0.0) {
1909 22
            if ($parsedComplex['imaginary'] == 0.0) {
1910 2
                return Functions::DIV0();
1911 20
            } elseif ($parsedComplex['imaginary'] < 0.0) {
1912 10
                return M_PI / -2;
1913
            }
1914
1915 10
            return M_PI / 2;
1916 106
        } elseif ($parsedComplex['real'] > 0.0) {
1917 52
            return atan($parsedComplex['imaginary'] / $parsedComplex['real']);
1918 54
        } elseif ($parsedComplex['imaginary'] < 0.0) {
1919 20
            return 0 - (M_PI - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real'])));
1920
        }
1921
1922 34
        return M_PI - atan($parsedComplex['imaginary'] / abs($parsedComplex['real']));
1923
    }
1924
1925
    /**
1926
     * IMCONJUGATE.
1927
     *
1928
     * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
1929
     *
1930
     * Excel Function:
1931
     *        IMCONJUGATE(complexNumber)
1932
     *
1933
     * @param    string $complexNumber the complex number for which you want the conjugate
1934
     *
1935
     * @return    string
1936
     */
1937 47
    public static function IMCONJUGATE($complexNumber)
1938
    {
1939 47
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1940
1941 47
        $parsedComplex = self::parseComplex($complexNumber);
1942
1943 47
        if ($parsedComplex['imaginary'] == 0.0) {
1944 9
            return $parsedComplex['real'];
1945
        }
1946
1947 38
        return self::cleanComplex(
1948 38
                self::COMPLEX(
1949 38
                    $parsedComplex['real'],
1950 38
                    0 - $parsedComplex['imaginary'],
1951 38
                    $parsedComplex['suffix']
1952
                )
1953
            );
1954
    }
1955
1956
    /**
1957
     * IMCOS.
1958
     *
1959
     * Returns the cosine of a complex number in x + yi or x + yj text format.
1960
     *
1961
     * Excel Function:
1962
     *        IMCOS(complexNumber)
1963
     *
1964
     * @param    string $complexNumber the complex number for which you want the cosine
1965
     *
1966
     * @return    string|float
1967
     */
1968 27 View Code Duplication
    public static function IMCOS($complexNumber)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1969
    {
1970 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
1971
1972 27
        $parsedComplex = self::parseComplex($complexNumber);
1973
1974 27
        if ($parsedComplex['imaginary'] == 0.0) {
1975 6
            return cos($parsedComplex['real']);
1976
        }
1977
1978 21
        return self::IMCONJUGATE(
1979 21
                self::COMPLEX(
1980 21
                    cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
1981 21
                    sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
1982 21
                    $parsedComplex['suffix']
1983
                )
1984
            );
1985
    }
1986
1987
    /**
1988
     * IMSIN.
1989
     *
1990
     * Returns the sine of a complex number in x + yi or x + yj text format.
1991
     *
1992
     * Excel Function:
1993
     *        IMSIN(complexNumber)
1994
     *
1995
     * @param    string $complexNumber the complex number for which you want the sine
1996
     *
1997
     * @return    string|float
1998
     */
1999 27 View Code Duplication
    public static function IMSIN($complexNumber)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2000
    {
2001 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2002
2003 27
        $parsedComplex = self::parseComplex($complexNumber);
2004
2005 27
        if ($parsedComplex['imaginary'] == 0.0) {
2006 6
            return sin($parsedComplex['real']);
2007
        }
2008
2009 21
        return self::COMPLEX(
2010 21
                sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
2011 21
                cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
2012 21
                $parsedComplex['suffix']
2013
            );
2014
    }
2015
2016
    /**
2017
     * IMSQRT.
2018
     *
2019
     * Returns the square root of a complex number in x + yi or x + yj text format.
2020
     *
2021
     * Excel Function:
2022
     *        IMSQRT(complexNumber)
2023
     *
2024
     * @param    string $complexNumber the complex number for which you want the square root
2025
     *
2026
     * @return    string
2027
     */
2028 28
    public static function IMSQRT($complexNumber)
2029
    {
2030 28
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2031
2032 28
        $parsedComplex = self::parseComplex($complexNumber);
2033
2034 28
        $theta = self::IMARGUMENT($complexNumber);
2035 28
        if ($theta === functions::DIV0()) {
2036 1
            return '0';
2037
        }
2038
2039 27
        $d1 = cos($theta / 2);
2040 27
        $d2 = sin($theta / 2);
2041 27
        $r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
2042
2043 27
        if ($parsedComplex['suffix'] == '') {
2044 5
            return self::COMPLEX($d1 * $r, $d2 * $r);
2045
        }
2046
2047 22
        return self::COMPLEX($d1 * $r, $d2 * $r, $parsedComplex['suffix']);
2048
    }
2049
2050
    /**
2051
     * IMLN.
2052
     *
2053
     * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
2054
     *
2055
     * Excel Function:
2056
     *        IMLN(complexNumber)
2057
     *
2058
     * @param    string $complexNumber the complex number for which you want the natural logarithm
2059
     *
2060
     * @return    string
2061
     */
2062 75
    public static function IMLN($complexNumber)
2063
    {
2064 75
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2065
2066 75
        $parsedComplex = self::parseComplex($complexNumber);
2067
2068 75
        if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2069 1
            return Functions::NAN();
2070
        }
2071
2072 74
        $logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
2073 74
        $t = self::IMARGUMENT($complexNumber);
2074
2075 74
        if ($parsedComplex['suffix'] == '') {
2076 8
            return self::COMPLEX($logR, $t);
2077
        }
2078
2079 66
        return self::COMPLEX($logR, $t, $parsedComplex['suffix']);
2080
    }
2081
2082
    /**
2083
     * IMLOG10.
2084
     *
2085
     * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
2086
     *
2087
     * Excel Function:
2088
     *        IMLOG10(complexNumber)
2089
     *
2090
     * @param    string $complexNumber the complex number for which you want the common logarithm
2091
     *
2092
     * @return    string
2093
     */
2094 27 View Code Duplication
    public static function IMLOG10($complexNumber)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2095
    {
2096 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2097
2098 27
        $parsedComplex = self::parseComplex($complexNumber);
2099
2100 27
        if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2101 1
            return Functions::NAN();
2102 26
        } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2103 2
            return log10($parsedComplex['real']);
2104
        }
2105
2106 24
        return self::IMPRODUCT(log10(EULER), self::IMLN($complexNumber));
2107
    }
2108
2109
    /**
2110
     * IMLOG2.
2111
     *
2112
     * Returns the base-2 logarithm of a complex number in x + yi or x + yj text format.
2113
     *
2114
     * Excel Function:
2115
     *        IMLOG2(complexNumber)
2116
     *
2117
     * @param    string $complexNumber the complex number for which you want the base-2 logarithm
2118
     *
2119
     * @return    string
2120
     */
2121 27 View Code Duplication
    public static function IMLOG2($complexNumber)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2122
    {
2123 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2124
2125 27
        $parsedComplex = self::parseComplex($complexNumber);
2126
2127 27
        if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2128 1
            return Functions::NAN();
2129 26
        } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2130 2
            return log($parsedComplex['real'], 2);
2131
        }
2132
2133 24
        return self::IMPRODUCT(log(EULER, 2), self::IMLN($complexNumber));
2134
    }
2135
2136
    /**
2137
     * IMEXP.
2138
     *
2139
     * Returns the exponential of a complex number in x + yi or x + yj text format.
2140
     *
2141
     * Excel Function:
2142
     *        IMEXP(complexNumber)
2143
     *
2144
     * @param    string $complexNumber the complex number for which you want the exponential
2145
     *
2146
     * @return    string
2147
     */
2148 27
    public static function IMEXP($complexNumber)
2149
    {
2150 27
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2151
2152 27
        $parsedComplex = self::parseComplex($complexNumber);
2153
2154 27
        if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
2155 1
            return '1';
2156
        }
2157
2158 26
        $e = exp($parsedComplex['real']);
2159 26
        $eX = $e * cos($parsedComplex['imaginary']);
2160 26
        $eY = $e * sin($parsedComplex['imaginary']);
2161
2162 26
        if ($parsedComplex['suffix'] == '') {
2163 4
            return self::COMPLEX($eX, $eY);
2164
        }
2165
2166 22
        return self::COMPLEX($eX, $eY, $parsedComplex['suffix']);
2167
    }
2168
2169
    /**
2170
     * IMPOWER.
2171
     *
2172
     * Returns a complex number in x + yi or x + yj text format raised to a power.
2173
     *
2174
     * Excel Function:
2175
     *        IMPOWER(complexNumber,realNumber)
2176
     *
2177
     * @param    string $complexNumber the complex number you want to raise to a power
2178
     * @param    float $realNumber the power to which you want to raise the complex number
2179
     *
2180
     * @return    string
2181
     */
2182
    public static function IMPOWER($complexNumber, $realNumber)
2183
    {
2184
        $complexNumber = Functions::flattenSingleValue($complexNumber);
2185
        $realNumber = Functions::flattenSingleValue($realNumber);
2186
2187
        if (!is_numeric($realNumber)) {
2188
            return Functions::VALUE();
2189
        }
2190
2191
        $parsedComplex = self::parseComplex($complexNumber);
2192
2193
        $r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']));
2194
        $rPower = pow($r, $realNumber);
2195
        $theta = self::IMARGUMENT($complexNumber) * $realNumber;
2196
        if ($theta == 0) {
2197
            return 1;
2198
        } elseif ($parsedComplex['imaginary'] == 0.0) {
2199
            return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
2200
        }
2201
2202
        return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
2203
    }
2204
2205
    /**
2206
     * IMDIV.
2207
     *
2208
     * Returns the quotient of two complex numbers in x + yi or x + yj text format.
2209
     *
2210
     * Excel Function:
2211
     *        IMDIV(complexDividend,complexDivisor)
2212
     *
2213
     * @param    string $complexDividend the complex numerator or dividend
2214
     * @param    string $complexDivisor the complex denominator or divisor
2215
     *
2216
     * @return    string
2217
     */
2218
    public static function IMDIV($complexDividend, $complexDivisor)
2219
    {
2220
        $complexDividend = Functions::flattenSingleValue($complexDividend);
2221
        $complexDivisor = Functions::flattenSingleValue($complexDivisor);
2222
2223
        $parsedComplexDividend = self::parseComplex($complexDividend);
2224
        $parsedComplexDivisor = self::parseComplex($complexDivisor);
2225
2226
        if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') &&
2227
            ($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])
2228
        ) {
2229
            return Functions::NAN();
2230
        }
2231
        if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) {
2232
            $parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix'];
2233
        }
2234
2235
        $d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']);
2236
        $d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']);
2237
        $d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']);
2238
2239
        $r = $d1 / $d3;
2240
        $i = $d2 / $d3;
2241
2242
        if ($i > 0.0) {
2243
            return self::cleanComplex($r . '+' . $i . $parsedComplexDivisor['suffix']);
2244
        } elseif ($i < 0.0) {
2245
            return self::cleanComplex($r . $i . $parsedComplexDivisor['suffix']);
2246
        }
2247
2248
        return $r;
2249
    }
2250
2251
    /**
2252
     * IMSUB.
2253
     *
2254
     * Returns the difference of two complex numbers in x + yi or x + yj text format.
2255
     *
2256
     * Excel Function:
2257
     *        IMSUB(complexNumber1,complexNumber2)
2258
     *
2259
     * @param    string $complexNumber1 the complex number from which to subtract complexNumber2
2260
     * @param    string $complexNumber2 the complex number to subtract from complexNumber1
2261
     *
2262
     * @return    string
2263
     */
2264
    public static function IMSUB($complexNumber1, $complexNumber2)
2265
    {
2266
        $complexNumber1 = Functions::flattenSingleValue($complexNumber1);
2267
        $complexNumber2 = Functions::flattenSingleValue($complexNumber2);
2268
2269
        $parsedComplex1 = self::parseComplex($complexNumber1);
2270
        $parsedComplex2 = self::parseComplex($complexNumber2);
2271
2272
        if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) &&
2273
            ($parsedComplex1['suffix'] != $parsedComplex2['suffix'])
2274
        ) {
2275
            return Functions::NAN();
2276
        } elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) {
2277
            $parsedComplex1['suffix'] = $parsedComplex2['suffix'];
2278
        }
2279
2280
        $d1 = $parsedComplex1['real'] - $parsedComplex2['real'];
2281
        $d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary'];
2282
2283
        return self::COMPLEX($d1, $d2, $parsedComplex1['suffix']);
2284
    }
2285
2286
    /**
2287
     * IMSUM.
2288
     *
2289
     * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
2290
     *
2291
     * Excel Function:
2292
     *        IMSUM(complexNumber[,complexNumber[,...]])
2293
     *
2294
     * @param    string $complexNumber,... Series of complex numbers to add
0 ignored issues
show
Bug introduced by
There is no parameter named $complexNumber,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2295
     *
2296
     * @return    string
2297
     */
2298 10
    public static function IMSUM()
2299
    {
2300
        // Return value
2301 10
        $returnValue = self::parseComplex('0');
2302 10
        $activeSuffix = '';
2303
2304
        // Loop through the arguments
2305 10
        $aArgs = Functions::flattenArray(func_get_args());
2306 10
        foreach ($aArgs as $arg) {
2307 10
            $parsedComplex = self::parseComplex($arg);
2308
2309 10 View Code Duplication
            if ($activeSuffix == '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2310 10
                $activeSuffix = $parsedComplex['suffix'];
2311 10
            } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
2312 2
                return Functions::NAN();
2313
            }
2314
2315 10
            $returnValue['real'] += $parsedComplex['real'];
2316 10
            $returnValue['imaginary'] += $parsedComplex['imaginary'];
2317
        }
2318
2319 8
        if ($returnValue['imaginary'] == 0.0) {
2320
            $activeSuffix = '';
2321
        }
2322
2323 8
        return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
2324
    }
2325
2326
    /**
2327
     * IMPRODUCT.
2328
     *
2329
     * Returns the product of two or more complex numbers in x + yi or x + yj text format.
2330
     *
2331
     * Excel Function:
2332
     *        IMPRODUCT(complexNumber[,complexNumber[,...]])
2333
     *
2334
     * @param    string $complexNumber,... Series of complex numbers to multiply
0 ignored issues
show
Bug introduced by
There is no parameter named $complexNumber,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2335
     *
2336
     * @return    string
2337
     */
2338 63
    public static function IMPRODUCT()
2339
    {
2340
        // Return value
2341 63
        $returnValue = self::parseComplex('1');
2342 63
        $activeSuffix = '';
2343
2344
        // Loop through the arguments
2345 63
        $aArgs = Functions::flattenArray(func_get_args());
2346 63
        foreach ($aArgs as $arg) {
2347 63
            $parsedComplex = self::parseComplex($arg);
2348
2349 63
            $workValue = $returnValue;
2350 63 View Code Duplication
            if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2351 63
                $activeSuffix = $parsedComplex['suffix'];
2352 62
            } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
2353 1
                return Functions::NAN();
2354
            }
2355 63
            $returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']);
2356 63
            $returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']);
2357
        }
2358
2359 62
        if ($returnValue['imaginary'] == 0.0) {
2360
            $activeSuffix = '';
2361
        }
2362
2363 62
        return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
2364
    }
2365
2366
    /**
2367
     *    DELTA.
2368
     *
2369
     *    Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
2370
     *    Use this function to filter a set of values. For example, by summing several DELTA
2371
     *    functions you calculate the count of equal pairs. This function is also known as the
2372
     *    Kronecker Delta function.
2373
     *
2374
     *    Excel Function:
2375
     *        DELTA(a[,b])
2376
     *
2377
     * @param    float $a the first number
2378
     * @param    float $b The second number. If omitted, b is assumed to be zero.
2379
     *
2380
     * @return    int
2381
     */
2382 25
    public static function DELTA($a, $b = 0)
2383
    {
2384 25
        $a = Functions::flattenSingleValue($a);
2385 25
        $b = Functions::flattenSingleValue($b);
2386
2387 25
        return (int) ($a == $b);
2388
    }
2389
2390
    /**
2391
     *    GESTEP.
2392
     *
2393
     *    Excel Function:
2394
     *        GESTEP(number[,step])
2395
     *
2396
     *    Returns 1 if number >= step; returns 0 (zero) otherwise
2397
     *    Use this function to filter a set of values. For example, by summing several GESTEP
2398
     *    functions you calculate the count of values that exceed a threshold.
2399
     *
2400
     * @param    float $number the value to test against step
2401
     * @param    float $step The threshold value.
2402
     *                                    If you omit a value for step, GESTEP uses zero.
2403
     *
2404
     * @return    int
2405
     */
2406 81
    public static function GESTEP($number, $step = 0)
2407
    {
2408 81
        $number = Functions::flattenSingleValue($number);
2409 81
        $step = Functions::flattenSingleValue($step);
2410
2411 81
        return (int) ($number >= $step);
2412
    }
2413
2414
    //
2415
    //    Private method to calculate the erf value
2416
    //
2417
    private static $twoSqrtPi = 1.128379167095512574;
2418
2419 148
    public static function erfVal($x)
2420
    {
2421 148
        if (abs($x) > 2.2) {
2422 67
            return 1 - self::erfcVal($x);
2423
        }
2424 123
        $sum = $term = $x;
2425 123
        $xsqr = ($x * $x);
2426 123
        $j = 1;
2427
        do {
2428 123
            $term *= $xsqr / $j;
2429 123
            $sum -= $term / (2 * $j + 1);
2430 123
            ++$j;
2431 123
            $term *= $xsqr / $j;
2432 123
            $sum += $term / (2 * $j + 1);
2433 123
            ++$j;
2434 123
            if ($sum == 0.0) {
2435 19
                break;
2436
            }
2437 112
        } while (abs($term / $sum) > PRECISION);
2438
2439 123
        return self::$twoSqrtPi * $sum;
2440
    }
2441
2442
    /**
2443
     *    ERF.
2444
     *
2445
     *    Returns the error function integrated between the lower and upper bound arguments.
2446
     *
2447
     *    Note: In Excel 2007 or earlier, if you input a negative value for the upper or lower bound arguments,
2448
     *            the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
2449
     *            improved, so that it can now calculate the function for both positive and negative ranges.
2450
     *            PhpSpreadsheet follows Excel 2010 behaviour, and accepts nagative arguments.
2451
     *
2452
     *    Excel Function:
2453
     *        ERF(lower[,upper])
2454
     *
2455
     * @param    float $lower lower bound for integrating ERF
2456
     * @param    float $upper upper bound for integrating ERF.
2457
     *                                If omitted, ERF integrates between zero and lower_limit
2458
     *
2459
     * @return    float
2460
     */
2461 123
    public static function ERF($lower, $upper = null)
2462
    {
2463 123
        $lower = Functions::flattenSingleValue($lower);
2464 123
        $upper = Functions::flattenSingleValue($upper);
2465
2466 123
        if (is_numeric($lower)) {
2467 120
            if (is_null($upper)) {
2468 37
                return self::erfVal($lower);
2469
            }
2470 83
            if (is_numeric($upper)) {
2471 83
                return self::erfVal($upper) - self::erfVal($lower);
2472
            }
2473
        }
2474
2475 3
        return Functions::VALUE();
2476
    }
2477
2478
    //
2479
    //    Private method to calculate the erfc value
2480
    //
2481
    private static $oneSqrtPi = 0.564189583547756287;
2482
2483 104
    private static function erfcVal($x)
2484
    {
2485 104
        if (abs($x) < 2.2) {
2486 28
            return 1 - self::erfVal($x);
2487
        }
2488 76
        if ($x < 0) {
2489 1
            return 2 - self::ERFC(-$x);
2490
        }
2491 76
        $a = $n = 1;
2492 76
        $b = $c = $x;
2493 76
        $d = ($x * $x) + 0.5;
2494 76
        $q1 = $q2 = $b / $d;
0 ignored issues
show
Unused Code introduced by
$q1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2495 76
        $t = 0;
0 ignored issues
show
Unused Code introduced by
$t is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2496
        do {
2497 76
            $t = $a * $n + $b * $x;
2498 76
            $a = $b;
2499 76
            $b = $t;
2500 76
            $t = $c * $n + $d * $x;
2501 76
            $c = $d;
2502 76
            $d = $t;
2503 76
            $n += 0.5;
2504 76
            $q1 = $q2;
2505 76
            $q2 = $b / $d;
2506 76
        } while ((abs($q1 - $q2) / $q2) > PRECISION);
2507
2508 76
        return self::$oneSqrtPi * exp(-$x * $x) * $q2;
2509
    }
2510
2511
    /**
2512
     *    ERFC.
2513
     *
2514
     *    Returns the complementary ERF function integrated between x and infinity
2515
     *
2516
     *    Note: In Excel 2007 or earlier, if you input a negative value for the lower bound argument,
2517
     *        the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
2518
     *        improved, so that it can now calculate the function for both positive and negative x values.
2519
     *            PhpSpreadsheet follows Excel 2010 behaviour, and accepts nagative arguments.
2520
     *
2521
     *    Excel Function:
2522
     *        ERFC(x)
2523
     *
2524
     * @param    float $x The lower bound for integrating ERFC
2525
     *
2526
     * @return    float
2527
     */
2528 41
    public static function ERFC($x)
2529
    {
2530 41
        $x = Functions::flattenSingleValue($x);
2531
2532 41
        if (is_numeric($x)) {
2533 38
            return self::erfcVal($x);
2534
        }
2535
2536 3
        return Functions::VALUE();
2537
    }
2538
2539
    /**
2540
     *    getConversionGroups
2541
     *    Returns a list of the different conversion groups for UOM conversions.
2542
     *
2543
     * @return    array
2544
     */
2545 1
    public static function getConversionGroups()
2546
    {
2547 1
        $conversionGroups = [];
2548 1
        foreach (self::$conversionUnits as $conversionUnit) {
2549 1
            $conversionGroups[] = $conversionUnit['Group'];
2550
        }
2551
2552 1
        return array_merge(array_unique($conversionGroups));
2553
    }
2554
2555
    /**
2556
     *    getConversionGroupUnits
2557
     *    Returns an array of units of measure, for a specified conversion group, or for all groups.
2558
     *
2559
     * @param    string $group The group whose units of measure you want to retrieve
2560
     *
2561
     * @return    array
2562
     */
2563 1
    public static function getConversionGroupUnits($group = null)
2564
    {
2565 1
        $conversionGroups = [];
2566 1
        foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
2567 1
            if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
2568 1
                $conversionGroups[$conversionGroup['Group']][] = $conversionUnit;
2569
            }
2570
        }
2571
2572 1
        return $conversionGroups;
2573
    }
2574
2575
    /**
2576
     *    getConversionGroupUnitDetails.
2577
     *
2578
     * @param    string $group The group whose units of measure you want to retrieve
2579
     *
2580
     * @return    array
2581
     */
2582 1
    public static function getConversionGroupUnitDetails($group = null)
2583
    {
2584 1
        $conversionGroups = [];
2585 1
        foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
2586 1
            if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
2587 1
                $conversionGroups[$conversionGroup['Group']][] = [
2588 1
                    'unit' => $conversionUnit,
2589 1
                    'description' => $conversionGroup['Unit Name'],
2590
                ];
2591
            }
2592
        }
2593
2594 1
        return $conversionGroups;
2595
    }
2596
2597
    /**
2598
     *    getConversionMultipliers
2599
     *    Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
2600
     *
2601
     * @return    array of mixed
2602
     */
2603 1
    public static function getConversionMultipliers()
2604
    {
2605 1
        return self::$conversionMultipliers;
2606
    }
2607
2608
    /**
2609
     *    CONVERTUOM.
2610
     *
2611
     *    Converts a number from one measurement system to another.
2612
     *    For example, CONVERT can translate a table of distances in miles to a table of distances
2613
     *    in kilometers.
2614
     *
2615
     *    Excel Function:
2616
     *        CONVERT(value,fromUOM,toUOM)
2617
     *
2618
     * @param    float $value the value in fromUOM to convert
2619
     * @param    string $fromUOM the units for value
2620
     * @param    string $toUOM the units for the result
2621
     *
2622
     * @return    float
2623
     */
2624 24
    public static function CONVERTUOM($value, $fromUOM, $toUOM)
2625
    {
2626 24
        $value = Functions::flattenSingleValue($value);
2627 24
        $fromUOM = Functions::flattenSingleValue($fromUOM);
2628 24
        $toUOM = Functions::flattenSingleValue($toUOM);
2629
2630 24
        if (!is_numeric($value)) {
2631 1
            return Functions::VALUE();
2632
        }
2633 23
        $fromMultiplier = 1.0;
2634 23 View Code Duplication
        if (isset(self::$conversionUnits[$fromUOM])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2635 16
            $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
2636
        } else {
2637 7
            $fromMultiplier = substr($fromUOM, 0, 1);
2638 7
            $fromUOM = substr($fromUOM, 1);
2639 7
            if (isset(self::$conversionMultipliers[$fromMultiplier])) {
2640 6
                $fromMultiplier = self::$conversionMultipliers[$fromMultiplier]['multiplier'];
2641
            } else {
2642 1
                return Functions::NA();
2643
            }
2644 6
            if ((isset(self::$conversionUnits[$fromUOM])) && (self::$conversionUnits[$fromUOM]['AllowPrefix'])) {
2645 5
                $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
2646
            } else {
2647 1
                return Functions::NA();
2648
            }
2649
        }
2650 21
        $value *= $fromMultiplier;
2651
2652 21
        $toMultiplier = 1.0;
2653 21 View Code Duplication
        if (isset(self::$conversionUnits[$toUOM])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2654 14
            $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
2655
        } else {
2656 7
            $toMultiplier = substr($toUOM, 0, 1);
2657 7
            $toUOM = substr($toUOM, 1);
2658 7
            if (isset(self::$conversionMultipliers[$toMultiplier])) {
2659 6
                $toMultiplier = self::$conversionMultipliers[$toMultiplier]['multiplier'];
2660
            } else {
2661 1
                return Functions::NA();
2662
            }
2663 6
            if ((isset(self::$conversionUnits[$toUOM])) && (self::$conversionUnits[$toUOM]['AllowPrefix'])) {
2664 5
                $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
2665
            } else {
2666 1
                return Functions::NA();
2667
            }
2668
        }
2669 19
        if ($unitGroup1 != $unitGroup2) {
2670 2
            return Functions::NA();
2671
        }
2672
2673 17
        if (($fromUOM == $toUOM) && ($fromMultiplier == $toMultiplier)) {
2674
            //    We've already factored $fromMultiplier into the value, so we need
2675
            //        to reverse it again
2676 3
            return $value / $fromMultiplier;
2677 14
        } elseif ($unitGroup1 == 'Temperature') {
2678 9
            if (($fromUOM == 'F') || ($fromUOM == 'fah')) {
2679 3
                if (($toUOM == 'F') || ($toUOM == 'fah')) {
2680 1
                    return $value;
2681
                }
2682 2
                $value = (($value - 32) / 1.8);
2683 2
                if (($toUOM == 'K') || ($toUOM == 'kel')) {
2684 1
                    $value += 273.15;
2685
                }
2686
2687 2
                return $value;
2688 6
            } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) &&
2689 6
                (($toUOM == 'K') || ($toUOM == 'kel'))
2690
            ) {
2691 1
                return $value;
2692 5
            } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) &&
2693 5
                (($toUOM == 'C') || ($toUOM == 'cel'))
2694
            ) {
2695 1
                return $value;
2696
            }
2697 4
            if (($toUOM == 'F') || ($toUOM == 'fah')) {
2698 2
                if (($fromUOM == 'K') || ($fromUOM == 'kel')) {
2699 1
                    $value -= 273.15;
2700
                }
2701
2702 2
                return ($value * 1.8) + 32;
2703
            }
2704 2
            if (($toUOM == 'C') || ($toUOM == 'cel')) {
2705 1
                return $value - 273.15;
2706
            }
2707
2708 1
            return $value + 273.15;
2709
        }
2710
2711 5
        return ($value * self::$unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier;
2712
    }
2713
}
2714