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