Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
4
 
5
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
6
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
7
 
8
class ConvertDecimal extends ConvertBase
9
{
10
    const LARGEST_OCTAL_IN_DECIMAL = 536870911;
11
    const SMALLEST_OCTAL_IN_DECIMAL = -536870912;
12
    const LARGEST_BINARY_IN_DECIMAL = 511;
13
    const SMALLEST_BINARY_IN_DECIMAL = -512;
14
    const LARGEST_HEX_IN_DECIMAL = 549755813887;
15
    const SMALLEST_HEX_IN_DECIMAL = -549755813888;
16
 
17
    /**
18
     * toBinary.
19
     *
20
     * Return a decimal value as binary.
21
     *
22
     * Excel Function:
23
     *        DEC2BIN(x[,places])
24
     *
25
     * @param array|bool|float|int|string $value The decimal integer you want to convert. If number is negative,
26
     *                          valid place values are ignored and DEC2BIN returns a 10-character
27
     *                          (10-bit) binary number in which the most significant bit is the sign
28
     *                          bit. The remaining 9 bits are magnitude bits. Negative numbers are
29
     *                          represented using two's-complement notation.
30
     *                      If number < -512 or if number > 511, DEC2BIN returns the #NUM! error
31
     *                          value.
32
     *                      If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
33
     *                      If DEC2BIN requires more than places characters, it returns the #NUM!
34
     *                          error value.
35
     *                      Or can be an array of values
36
     * @param null|array|float|int|string $places The number of characters to use. If places is omitted, DEC2BIN uses
37
     *                          the minimum number of characters necessary. Places is useful for
38
     *                          padding the return value with leading 0s (zeros).
39
     *                      If places is not an integer, it is truncated.
40
     *                      If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
41
     *                      If places is zero or negative, DEC2BIN returns the #NUM! error value.
42
     *                      Or can be an array of values
43
     *
44
     * @return array|string Result, or an error
45
     *         If an array of numbers is passed as an argument, then the returned result will also be an array
46
     *            with the same dimensions
47
     */
48
    public static function toBinary($value, $places = null): array|string
49
    {
50
        if (is_array($value) || is_array($places)) {
51
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
52
        }
53
 
54
        try {
55
            $value = self::validateValue($value);
56
            $value = self::validateDecimal($value);
57
            $places = self::validatePlaces($places);
58
        } catch (Exception $e) {
59
            return $e->getMessage();
60
        }
61
 
62
        $value = (int) floor((float) $value);
63
        if ($value > self::LARGEST_BINARY_IN_DECIMAL || $value < self::SMALLEST_BINARY_IN_DECIMAL) {
64
            return ExcelError::NAN();
65
        }
66
 
67
        $r = decbin($value);
68
        // Two's Complement
69
        $r = substr($r, -10);
70
 
71
        return self::nbrConversionFormat($r, $places);
72
    }
73
 
74
    /**
75
     * toHex.
76
     *
77
     * Return a decimal value as hex.
78
     *
79
     * Excel Function:
80
     *        DEC2HEX(x[,places])
81
     *
82
     * @param array|bool|float|int|string $value The decimal integer you want to convert. If number is negative,
83
     *                          places is ignored and DEC2HEX returns a 10-character (40-bit)
84
     *                          hexadecimal number in which the most significant bit is the sign
85
     *                          bit. The remaining 39 bits are magnitude bits. Negative numbers
86
     *                          are represented using two's-complement notation.
87
     *                      If number < -549,755,813,888 or if number > 549,755,813,887,
88
     *                          DEC2HEX returns the #NUM! error value.
89
     *                      If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
90
     *                      If DEC2HEX requires more than places characters, it returns the
91
     *                          #NUM! error value.
92
     *                      Or can be an array of values
93
     * @param null|array|float|int|string $places The number of characters to use. If places is omitted, DEC2HEX uses
94
     *                          the minimum number of characters necessary. Places is useful for
95
     *                          padding the return value with leading 0s (zeros).
96
     *                      If places is not an integer, it is truncated.
97
     *                      If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
98
     *                      If places is zero or negative, DEC2HEX returns the #NUM! error value.
99
     *                      Or can be an array of values
100
     *
101
     * @return array|string Result, or an error
102
     *         If an array of numbers is passed as an argument, then the returned result will also be an array
103
     *            with the same dimensions
104
     */
105
    public static function toHex($value, $places = null): array|string
106
    {
107
        if (is_array($value) || is_array($places)) {
108
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
109
        }
110
 
111
        try {
112
            $value = self::validateValue($value);
113
            $value = self::validateDecimal($value);
114
            $places = self::validatePlaces($places);
115
        } catch (Exception $e) {
116
            return $e->getMessage();
117
        }
118
 
119
        $value = floor((float) $value);
120
        if ($value > self::LARGEST_HEX_IN_DECIMAL || $value < self::SMALLEST_HEX_IN_DECIMAL) {
121
            return ExcelError::NAN();
122
        }
123
        $r = strtoupper(dechex((int) $value));
124
        $r = self::hex32bit($value, $r);
125
 
126
        return self::nbrConversionFormat($r, $places);
127
    }
128
 
129
    public static function hex32bit(float $value, string $hexstr, bool $force = false): string
130
    {
131
        if (PHP_INT_SIZE === 4 || $force) {
132
            if ($value >= 2 ** 32) {
133
                $quotient = (int) ($value / (2 ** 32));
134
 
135
                return strtoupper(substr('0' . dechex($quotient), -2) . $hexstr);
136
            }
137
            if ($value < -(2 ** 32)) {
138
                $quotient = 256 - (int) ceil((-$value) / (2 ** 32));
139
 
140
                return strtoupper(substr('0' . dechex($quotient), -2) . substr("00000000$hexstr", -8));
141
            }
142
            if ($value < 0) {
143
                return "FF$hexstr";
144
            }
145
        }
146
 
147
        return $hexstr;
148
    }
149
 
150
    /**
151
     * toOctal.
152
     *
153
     * Return an decimal value as octal.
154
     *
155
     * Excel Function:
156
     *        DEC2OCT(x[,places])
157
     *
158
     * @param array|bool|float|int|string $value The decimal integer you want to convert. If number is negative,
159
     *                          places is ignored and DEC2OCT returns a 10-character (30-bit)
160
     *                          octal number in which the most significant bit is the sign bit.
161
     *                          The remaining 29 bits are magnitude bits. Negative numbers are
162
     *                          represented using two's-complement notation.
163
     *                      If number < -536,870,912 or if number > 536,870,911, DEC2OCT
164
     *                          returns the #NUM! error value.
165
     *                      If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
166
     *                      If DEC2OCT requires more than places characters, it returns the
167
     *                          #NUM! error value.
168
     *                      Or can be an array of values
169
     * @param array|int $places The number of characters to use. If places is omitted, DEC2OCT uses
170
     *                          the minimum number of characters necessary. Places is useful for
171
     *                          padding the return value with leading 0s (zeros).
172
     *                      If places is not an integer, it is truncated.
173
     *                      If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
174
     *                      If places is zero or negative, DEC2OCT returns the #NUM! error value.
175
     *                      Or can be an array of values
176
     *
177
     * @return array|string Result, or an error
178
     *         If an array of numbers is passed as an argument, then the returned result will also be an array
179
     *            with the same dimensions
180
     */
181
    public static function toOctal($value, $places = null): array|string
182
    {
183
        if (is_array($value) || is_array($places)) {
184
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $places);
185
        }
186
 
187
        try {
188
            $value = self::validateValue($value);
189
            $value = self::validateDecimal($value);
190
            $places = self::validatePlaces($places);
191
        } catch (Exception $e) {
192
            return $e->getMessage();
193
        }
194
 
195
        $value = (int) floor((float) $value);
196
        if ($value > self::LARGEST_OCTAL_IN_DECIMAL || $value < self::SMALLEST_OCTAL_IN_DECIMAL) {
197
            return ExcelError::NAN();
198
        }
199
        $r = decoct($value);
200
        $r = substr($r, -10);
201
 
202
        return self::nbrConversionFormat($r, $places);
203
    }
204
 
205
    protected static function validateDecimal(string $value): string
206
    {
207
        if (strlen($value) > preg_match_all('/[-0123456789.]/', $value)) {
208
            throw new Exception(ExcelError::VALUE());
209
        }
210
 
211
        return $value;
212
    }
213
}