• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16package std.core;
17
18/**
19 * Represents boxed float value and related operations
20 */
21export final class Float extends Floating implements Comparable<Float>, JSONable<Float> {
22    private value: float;
23
24    /**
25     * Constructs a new Float instance with initial value zero
26     */
27    public constructor() {
28        this.value = 0.0;
29    }
30
31    /**
32     * Constructs a new Float instance with provided initial value
33     *
34     * @param value the initial value
35     */
36    public constructor(value: float) {
37        this.value = value;
38    }
39
40    /**
41     * Constructs a new Float instance with provided initial value (`double` type literal)
42     *
43     * @param value the initial value
44     */
45    public constructor(value: double) {
46        this.value = value as float;
47    }
48
49
50    /**
51     * Constructs a new Float instance with provided initial value
52     *
53     * @param value the initial value
54     */
55    public constructor(value: Float) {
56        this.value = value.floatValue();
57    }
58
59    /**
60     * Returns value of this instance as a primitive
61     *
62     * @returns value of this instance
63     */
64    public unboxed(): float {
65        return this.value;
66    }
67
68    /**
69     * Returns boxed representation of the primitive
70     *
71     * @param value value to box
72     *
73     * @returns boxed value
74     */
75    public static valueOf(value: float): Float {
76        // TODO(ivan-tyulyandin): caching is possible
77        return new Float(value);
78    }
79
80    /**
81     * Minimal value that this type can have as a float
82     */
83    public static readonly MIN_VALUE: float = 1.4e-45;
84
85    /**
86     * Maximal value that this type can have as a float
87     */
88    public static readonly MAX_VALUE: float = 3.4028235e+38 as float;
89
90    /**
91     * Maximal integer value that can be used as a float without loss of precision
92     */
93    public static readonly MAX_SAFE_INTEGER = 16777215;
94
95    /**
96     * Size of this type in bits
97     */
98    public static readonly BIT_SIZE: byte = 32;
99
100    /**
101     * Size of this type in bytes
102     */
103    public static readonly BYTE_SIZE: byte = 4;
104
105
106    /**
107     * Represents the NaN value according to IEEE-754 specification
108     */
109    public static readonly NaN: float = 0.0 / 0.0;
110
111    /**
112     * Represents the +Infinity value according to IEEE-754 specification
113     */
114    public static readonly POSITIVE_INFINITY: float = 1.0 / 0.0;
115
116    /**
117     * Represents the -Infinity value according to IEEE-754 specification
118     */
119    public static readonly NEGATIVE_INFINITY: float = -1.0 / 0.0;
120
121    /**
122     * Number of significant precision bits in this floating type
123     */
124    public static readonly PRECISION: byte = 24;
125
126    /**
127     * Minimal possible difference between two float values
128     * For float (IEEE-754 binary32) it is 2^(-23) and its bit representation is 0x34000000.
129     */
130    public static readonly DELTA: float = Float.bitCastFromInt(0x34000000);
131
132    /**
133     * Minimal possible difference between two float values
134     */
135    public static readonly EPSILON: float = Float.DELTA;
136
137    /**
138     * Returns value of this instance
139     *
140     * @returns value as byte
141     */
142    public override byteValue(): byte {
143        return this.value as byte;
144    }
145
146    /**
147     * Returns value of this instance
148     *
149     * @returns value as short
150     */
151    public override shortValue(): short {
152        return this.value as short;
153    }
154
155    /**
156     * Returns value of this instance
157     *
158     * @returns value as int
159     */
160    public override intValue(): int {
161        return this.value as int;
162    }
163
164    /**
165     * Returns value of this instance
166     *
167     * @returns value as long
168     */
169    public override longValue(): long {
170        return this.value as long;
171    }
172
173    /**
174     * Returns value of this instance
175     *
176     * @returns value as float
177     */
178    public override floatValue(): float {
179        return this.value;
180    }
181
182    /**
183     * Returns value of this instance
184     *
185     * @returns value as double
186     */
187    public override doubleValue(): double {
188        return this.value as double;
189    }
190
191    /**
192     * Compares this instance to other Float object
193     * The result is less than 0 if this instance lesser than provided object
194     * 0 if they are equal
195     * and greater than 0 otherwise.
196     *
197     * @param other Float object to compare with
198     *
199     * @returns result of the comparison
200     */
201    public override compareTo(other: Float): int {
202        return (this.value - other.unboxed()) as int;
203    }
204
205    /**
206     * toString(f: float, r: int): String -- returns a string representation of f by radix r
207     */
208    public static native toString(f: float, r: int): String;
209
210    /**
211     * toString(f: float): String -- returns a string representation of f by radix 10
212     */
213    public static toString(f: float): String {
214        return Float.toString(f, 10);
215    }
216
217    /**
218     * Converts this object to a string
219     *
220     * @returns result of the conversion by radix r
221     */
222    public toString(r: int): String {
223        return Float.toString(this.value, r);
224    }
225
226    /**
227     * Converts this object to a string
228     *
229     * @returns result of the conversion by radix 10
230     */
231    public override toString(): String {
232        return Float.toString(this.value, 10);
233    }
234
235    /**
236     * Returns a hash code (integer representation) for this instance
237     *
238     * @returns representation of this instance
239     */
240    public override $_hashCode(): int {
241        return this.intValue();
242    }
243
244    /**
245     * compare(float, float) checks if two floats are differs no more than by Float.DELTA
246     *
247     * @param lhs left-hand side float for comparison
248     *
249     * @param rhs right-hand side float for comparison
250     *
251     * @returns true if lhs and rhs are equal with respect to Float.DELTA
252     */
253    public static compare(lhs: float, rhs: float): boolean {
254        return (abs(lhs - rhs) <= Float.DELTA)
255    }
256
257    /**
258     * Checks for equality this instance with provided object, treated as a Float
259     *
260     * @param other object to be checked against
261     *
262     * @returns true if provided object and this instance have same value, false otherwise
263     * Returns false if type of provided object is not the same as this type
264     */
265    public equals(other: NullishType): boolean {
266        if (__runtimeIsSameReference(this, other)) {
267            return true
268        }
269
270        if (!(other instanceof Float)) {
271            return false
272        }
273
274        return this.value == (other as Float).value
275    }
276
277    /**
278     * Checks if float is NaN (not a number)
279     *
280     * @param v the float to test
281     *
282     * @returns true if the argument is NaN
283     */
284    public static isNaN(v: float): boolean {
285        // IEEE-754 feature
286        return v != v;
287    }
288
289    /**
290     * Checks if the underlying float is NaN (not a number)
291     *
292     * @returns true if the underlying float is NaN
293     */
294    public isNaN(): boolean {
295        return Float.isNaN(this.value);
296    }
297
298    /**
299     * Checks if float is a floating point value (not a NaN or infinity)
300     *
301     * @param v the float to test
302     *
303     * @returns true if the argument is a floating point value
304     */
305    public static isFinite(v: float): boolean {
306        return !(Float.isNaN(v) || (v == Float.POSITIVE_INFINITY) || (v == Float.NEGATIVE_INFINITY));
307    }
308
309    /**
310     * Checks if the underlying float is a floating point value (not a NaN or infinity)
311     *
312     * @returns true if the underlying float is a floating point value
313     */
314    public isFinite(): boolean {
315        return Float.isFinite(this.value);
316    }
317
318    /**
319     * Checks if float is similar to an integer value
320     *
321     * @param v the float to test
322     *
323     * @returns true if the argument is similar to an integer value
324     */
325    public static isInteger(v: float): boolean {
326        // In the language % works as C fmod that differs with IEEE-754 % definition
327        return Float.compare(v % (1.0 as float), 0.0 as float);
328    }
329
330    /**
331     * Checks if the underlying float is similar to an integer value
332     *
333     * @returns true if the underlying float is similar to an integer value
334     */
335    public isInteger(): boolean {
336        return Float.isInteger(this.value);
337    }
338
339    /**
340     * Checks if float is a safe integer value
341     *
342     * @param v the float to test
343     *
344     * @returns true if the argument is integer ans less than MAX_SAFE_INTEGER
345     */
346    public static isSafeInteger(v: float): boolean {
347        return Float.isInteger(v) && (abs(v) <= Float.MAX_SAFE_INTEGER);
348    }
349
350    /*
351     * Checks if float is a safe integer value
352     *
353     * @returns true if the underlying float is a safe integer
354     */
355    public isSafeInteger(): boolean {
356        return Float.isSafeInteger(this.value);
357    }
358
359    /**
360     * Performs floating point addition of this instance with provided one, returns the result as new instance
361     *
362     * @param other Right hand side of the addition
363     *
364     * @returns Result of the addition
365     */
366    public add(other: Float): Float {
367        return Float.valueOf((this.value + other.floatValue()) as float)
368    }
369
370    /**
371     * Performs floating point subtraction of this instance with provided one, returns the result as new instance
372     *
373     * @param other Right hand side of the subtraction
374     *
375     * @returns Result of the subtraction
376     */
377    public sub(other: Float): Float {
378        return Float.valueOf((this.value - other.floatValue()) as float)
379    }
380
381    /**
382     * Performs floating point multiplication of this instance with provided one, returns the result as new instance
383     *
384     * @param other Right hand side of the multiplication
385     *
386     * @returns Result of the multiplication
387     */
388    public mul(other: Float): Float {
389        return Float.valueOf((this.value * other.floatValue()) as float)
390    }
391
392    /**
393     * Performs floating point division of this instance with provided one, returns the result as new instance
394     *
395     * @param other Right hand side of the division
396     *
397     * @returns Result of the division
398     */
399    public div(other: Float): Float {
400        return Float.valueOf((this.value / other.floatValue()) as float)
401    }
402
403    /**
404     * Checks if this instance value is less than value of provided instance
405     *
406     * @param other Right hand side of the comparison
407     *
408     * @returns true if this value is less than provided, false otherwise
409     */
410    public isLessThan(other: Float): boolean {
411        return this.value < other.floatValue();
412    }
413
414    /**
415     * Checks if this instance value is less than or equal to value of provided instance
416     *
417     * @param other Right hand side of the comparison
418     *
419     * @returns true if this value is less than or equal to provided, false otherwise
420     */
421    public isLessEqualThan(other: Float): boolean {
422        return this.value <= other.floatValue();
423    }
424
425    /**
426     * Checks if this instance value is greater than value of provided instance
427     *
428     * @param other Right hand side of the comparison
429     *
430     * @returns true if this value is greater than provided, false otherwise
431     */
432    public isGreaterThan(other: Float): boolean {
433        return this.value > other.floatValue();
434    }
435
436    /**
437     * Checks if this instance value is greater than or equal to value of provided instance
438     *
439     * @param other Right hand side of the comparison
440     *
441     * @returns true if this value is greater than or equal to provided, false otherwise
442     */
443    public isGreaterEqualThan(other: Float): boolean {
444        return this.value >= other.floatValue();
445    }
446
447    /**
448     * Converts bit representation to corresponding IEEE-754 floating point representation
449     * @param bits bits to convert
450     *
451     * @returns float - converted value
452     */
453    public static native bitCastFromInt(bits: int): float
454
455    /**
456     * Converts IEEE-754 floating point representation to corresponding bit representation
457     * @param val value to convert
458     *
459     * @returns int - bit representation
460     */
461    public static native bitCastToInt(val: float): int
462
463    /**
464     * Creates a Float instance based on JSONValue
465     *
466     * @param json: JSONValue - a JSON representation
467     *
468     * @throws JSONTypeError if json does not encode a valid float
469     *
470     * @returns Float - float value decoded from JSON
471     */
472    static createFromJSONValue(json: JSONValue): Float {
473        if (json instanceof JSONNumber) {
474            let val = (json as JSONNumber).value
475            if (-Float.MAX_VALUE <= val && val <= Float.MAX_VALUE) {
476                return Float.valueOf((json as JSONNumber).value as float)
477            }
478        }
479        throw new JSONTypeError("Cannot create Double from JSON", new ErrorOptions(json as Object))
480    }
481}
482