checked.ha (13297B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use math; 5 use types; 6 7 // Adds 'a' and 'b', returning the result and whether overflow occurred. 8 export fn addi8(a: i8, b: i8) (i8, bool) = { 9 const res = a + b; 10 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 11 return (res, overflow); 12 }; 13 14 @test fn addi8() void = { 15 const (res, overflow) = addi8(100, 20); 16 assert(res == 120); 17 assert(!overflow); 18 const (res, overflow) = addi8(100, 50); 19 assert(res == -106); 20 assert(overflow); 21 }; 22 23 // Adds 'a' and 'b', returning the result and whether overflow occurred. 24 export fn addi16(a: i16, b: i16) (i16, bool) = { 25 const res = a + b; 26 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 27 return (res, overflow); 28 }; 29 30 @test fn addi16() void = { 31 const (res, overflow) = addi16(32700, 60); 32 assert(res == 32760); 33 assert(!overflow); 34 const (res, overflow) = addi16(32700, 100); 35 assert(res == -32736); 36 assert(overflow); 37 }; 38 39 // Adds 'a' and 'b', returning the result and whether overflow occurred. 40 export fn addi32(a: i32, b: i32) (i32, bool) = { 41 const res = a + b; 42 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 43 return (res, overflow); 44 }; 45 46 @test fn addi32() void = { 47 const (res, overflow) = addi32(2147483600, 40); 48 assert(res == 2147483640); 49 assert(!overflow); 50 const (res, overflow) = addi32(2147483600, 100); 51 assert(res == -2147483596); 52 assert(overflow); 53 }; 54 55 // Adds 'a' and 'b', returning the result and whether overflow occurred. 56 export fn addi64(a: i64, b: i64) (i64, bool) = { 57 const res = a + b; 58 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 59 return (res, overflow); 60 }; 61 62 @test fn addi64() void = { 63 const (res, overflow) = addi64(9223372036854775800, 5); 64 assert(res == 9223372036854775805); 65 assert(!overflow); 66 const (res, overflow) = addi64(9223372036854775800, 10); 67 assert(res == -9223372036854775806); 68 assert(overflow); 69 }; 70 71 // Adds 'a' and 'b', returning the result and whether overflow occurred. 72 export fn addi(a: int, b: int) (int, bool) = { 73 const res = a + b; 74 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 75 return (res, overflow); 76 }; 77 78 // Adds 'a' and 'b', returning the result and whether overflow occurred. 79 export fn addu8(a: u8, b: u8) (u8, bool) = { 80 const res = a + b; 81 const overflow = res < a; 82 return (res, overflow); 83 }; 84 85 @test fn addu8() void = { 86 const (res, overflow) = addu8(200, 50); 87 assert(res == 250); 88 assert(!overflow); 89 const (res, overflow) = addu8(200, 100); 90 assert(res == 44); 91 assert(overflow); 92 }; 93 94 // Adds 'a' and 'b', returning the result and whether overflow occurred. 95 export fn addu16(a: u16, b: u16) (u16, bool) = { 96 const res = a + b; 97 const overflow = res < a; 98 return (res, overflow); 99 }; 100 101 @test fn addu16() void = { 102 const (res, overflow) = addu16(65500, 30); 103 assert(res == 65530); 104 assert(!overflow); 105 const (res, overflow) = addu16(65500, 50); 106 assert(res == 14); 107 assert(overflow); 108 }; 109 110 // Adds 'a' and 'b', returning the result and whether overflow occurred. 111 export fn addu32(a: u32, b: u32) (u32, bool) = { 112 const res = a + b; 113 const overflow = res < a; 114 return (res, overflow); 115 }; 116 117 @test fn addu32() void = { 118 const (res, overflow) = addu32(4294967200, 90); 119 assert(res == 4294967290); 120 assert(!overflow); 121 const (res, overflow) = addu32(4294967200, 100); 122 assert(res == 4); 123 assert(overflow); 124 }; 125 126 // Adds 'a' and 'b', returning the result and whether overflow occurred. 127 export fn addu64(a: u64, b: u64) (u64, bool) = { 128 const res = a + b; 129 const overflow = res < a; 130 return (res, overflow); 131 }; 132 133 @test fn addu64() void = { 134 const (res, overflow) = addu64(18446744073709551600, 10); 135 assert(res == 18446744073709551610); 136 assert(!overflow); 137 const (res, overflow) = addu64(18446744073709551610, 50); 138 assert(res == 44); 139 assert(overflow); 140 }; 141 142 // Adds 'a' and 'b', returning the result and whether overflow occurred. 143 export fn addu(a: uint, b: uint) (uint, bool) = { 144 const res = a + b; 145 const overflow = res < a; 146 return (res, overflow); 147 }; 148 149 // Adds 'a' and 'b', returning the result and whether overflow occurred. 150 export fn addz(a: size, b: size) (size, bool) = { 151 const res = a + b; 152 const overflow = res < a; 153 return (res, overflow); 154 }; 155 156 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 157 export fn subi8(a: i8, b: i8) (i8, bool) = { 158 const res = a - b; 159 const overflow = a < 0 != b < 0 && a < 0 != res < 0; 160 return (res, overflow); 161 }; 162 163 @test fn subi8() void = { 164 const (res, overflow) = subi8(-100, 20); 165 assert(res == -120); 166 assert(!overflow); 167 const (res, overflow) = subi8(-100, 50); 168 assert(res == 106); 169 assert(overflow); 170 const (res, overflow) = subi8(types::I8_MAX, types::I8_MIN); 171 assert(res == -1); 172 assert(overflow); 173 }; 174 175 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 176 export fn subi16(a: i16, b: i16) (i16, bool) = { 177 const res = a - b; 178 const overflow = a < 0 != b < 0 && a < 0 != res < 0; 179 return (res, overflow); 180 }; 181 182 @test fn subi16() void = { 183 const (res, overflow) = subi16(-32700, 60); 184 assert(res == -32760); 185 assert(!overflow); 186 const (res, overflow) = subi16(-32700, 100); 187 assert(res == 32736); 188 assert(overflow); 189 const (res, overflow) = subi16(types::I16_MAX, types::I16_MIN); 190 assert(res == -1); 191 assert(overflow); 192 }; 193 194 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 195 export fn subi32(a: i32, b: i32) (i32, bool) = { 196 const res = a - b; 197 const overflow = a < 0 != b < 0 && a < 0 != res < 0; 198 return (res, overflow); 199 }; 200 201 @test fn subi32() void = { 202 const (res, overflow) = subi32(-2147483600, 40); 203 assert(res == -2147483640); 204 assert(!overflow); 205 const (res, overflow) = subi32(-2147483600, 100); 206 assert(res == 2147483596); 207 assert(overflow); 208 const (res, overflow) = subi32(types::I32_MAX, types::I32_MIN); 209 assert(res == -1); 210 assert(overflow); 211 }; 212 213 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 214 export fn subi64(a: i64, b: i64) (i64, bool) = { 215 const res = a - b; 216 const overflow = a < 0 != b < 0 && a < 0 != res < 0; 217 return (res, overflow); 218 }; 219 220 @test fn subi64() void = { 221 const (res, overflow) = subi64(-9223372036854775800, 5); 222 assert(res == -9223372036854775805); 223 assert(!overflow); 224 const (res, overflow) = subi64(-9223372036854775800, 10); 225 assert(res == 9223372036854775806); 226 assert(overflow); 227 const (res, overflow) = subi64(types::I64_MAX, types::I64_MIN); 228 assert(res == -1); 229 assert(overflow); 230 }; 231 232 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 233 export fn subi(a: int, b: int) (int, bool) = { 234 const res = a - b; 235 const overflow = a < 0 != b < 0 && a < 0 != res < 0; 236 return (res, overflow); 237 }; 238 239 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 240 export fn subu8(a: u8, b: u8) (u8, bool) = { 241 const res = a - b; 242 const overflow = res > a; 243 return (res, overflow); 244 }; 245 246 @test fn subu8() void = { 247 const (res, overflow) = subu8(250, 50); 248 assert(res == 200); 249 assert(!overflow); 250 const (res, overflow) = subu8(44, 100); 251 assert(res == 200); 252 assert(overflow); 253 }; 254 255 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 256 export fn subu16(a: u16, b: u16) (u16, bool) = { 257 const res = a - b; 258 const overflow = res > a; 259 return (res, overflow); 260 }; 261 262 @test fn subu16() void = { 263 const (res, overflow) = subu16(65530, 30); 264 assert(res == 65500); 265 assert(!overflow); 266 const (res, overflow) = subu16(14, 50); 267 assert(res == 65500); 268 assert(overflow); 269 }; 270 271 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 272 export fn subu32(a: u32, b: u32) (u32, bool) = { 273 const res = a - b; 274 const overflow = res > a; 275 return (res, overflow); 276 }; 277 278 @test fn subu32() void = { 279 const (res, overflow) = subu32(4294967290, 90); 280 assert(res == 4294967200); 281 assert(!overflow); 282 const (res, overflow) = subu32(4, 100); 283 assert(res == 4294967200); 284 assert(overflow); 285 }; 286 287 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 288 export fn subu64(a: u64, b: u64) (u64, bool) = { 289 const res = a - b; 290 const overflow = res > a; 291 return (res, overflow); 292 }; 293 294 @test fn subu64() void = { 295 const (res, overflow) = subu64(18446744073709551610, 10); 296 assert(res == 18446744073709551600); 297 assert(!overflow); 298 const (res, overflow) = subu64(44, 50); 299 assert(res == 18446744073709551610); 300 assert(overflow); 301 }; 302 303 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 304 export fn subu(a: uint, b: uint) (uint, bool) = { 305 const res = a - b; 306 const overflow = res > a; 307 return (res, overflow); 308 }; 309 310 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 311 export fn subz(a: size, b: size) (size, bool) = { 312 const res = a - b; 313 const overflow = res > a; 314 return (res, overflow); 315 }; 316 317 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 318 export fn muli8(a: i8, b: i8) (i8, bool) = { 319 const fullres = a: int * b: int; 320 const res = fullres: i8; 321 const overflow = res != fullres; 322 return (res, overflow); 323 }; 324 325 @test fn muli8() void = { 326 const (res, overflow) = muli8(11, 11); 327 assert(res == 121); 328 assert(!overflow); 329 const (res, overflow) = muli8(12, 12); 330 assert(res == -112); 331 assert(overflow); 332 }; 333 334 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 335 export fn muli16(a: i16, b: i16) (i16, bool) = { 336 const fullres = a: int * b: int; 337 const res = fullres: i16; 338 const overflow = res != fullres; 339 return (res, overflow); 340 }; 341 342 @test fn muli16() void = { 343 const (res, overflow) = muli16(181, 181); 344 assert(res == 32761); 345 assert(!overflow); 346 const (res, overflow) = muli16(182, 182); 347 assert(res == -32412); 348 assert(overflow); 349 }; 350 351 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 352 export fn muli32(a: i32, b: i32) (i32, bool) = { 353 const fullres = a: i64 * b: i64; 354 const res = fullres: i32; 355 const overflow = res != fullres; 356 return (res, overflow); 357 }; 358 359 @test fn muli32() void = { 360 const (res, overflow) = muli32(46340, 46340); 361 assert(res == 2147395600); 362 assert(!overflow); 363 const (res, overflow) = muli32(46341, 46341); 364 assert(res == -2147479015); 365 assert(overflow); 366 }; 367 368 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 369 export fn muli64(a: i64, b: i64) (i64, bool) = { 370 const (hi, lo) = math::mulu64(math::absi64(a), math::absi64(b)); 371 const res = a * b; 372 const overflow = hi != 0 || lo & (1 << 63) != 0; 373 return (res, overflow); 374 }; 375 376 @test fn muli64() void = { 377 const (res, overflow) = muli64(3037000499, 3037000499); 378 assert(res == 9223372030926249001); 379 assert(!overflow); 380 const (res, overflow) = muli64(3037000500, 3037000500); 381 assert(res == -9223372036709301616); 382 assert(overflow); 383 }; 384 385 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 386 export fn muli(a: int, b: int) (int, bool) = { 387 if (size(int) == 4) { 388 const ret = muli32(a: i32, b: i32); 389 return (ret.0, ret.1); 390 } else { 391 const ret = muli64(a, b); 392 return (ret.0: int, ret.1); 393 }; 394 }; 395 396 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 397 export fn mulu8(a: u8, b: u8) (u8, bool) = { 398 const fullres = a: uint * b: uint; 399 const res = fullres: u8; 400 const overflow = res != fullres; 401 return (res, overflow); 402 }; 403 404 @test fn mulu8() void = { 405 const (res, overflow) = mulu8(15, 15); 406 assert(res == 225); 407 assert(!overflow); 408 const (res, overflow) = mulu8(16, 16); 409 assert(res == 0); 410 assert(overflow); 411 }; 412 413 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 414 export fn mulu16(a: u16, b: u16) (u16, bool) = { 415 const fullres = a: uint * b: uint; 416 const res = fullres: u16; 417 const overflow = res != fullres; 418 return (res, overflow); 419 }; 420 421 @test fn mulu16() void = { 422 const (res, overflow) = mulu16(255, 255); 423 assert(res == 65025); 424 assert(!overflow); 425 const (res, overflow) = mulu16(256, 256); 426 assert(res == 0); 427 assert(overflow); 428 }; 429 430 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 431 export fn mulu32(a: u32, b: u32) (u32, bool) = { 432 const fullres = a: u64 * b: u64; 433 const res = fullres: u32; 434 const overflow = res != fullres; 435 return (res, overflow); 436 }; 437 438 @test fn mulu32() void = { 439 const (res, overflow) = mulu32(65535, 65535); 440 assert(res == 4294836225); 441 assert(!overflow); 442 const (res, overflow) = mulu32(65536, 65536); 443 assert(res == 0); 444 assert(overflow); 445 }; 446 447 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 448 export fn mulu64(a: u64, b: u64) (u64, bool) = { 449 const (hi, lo) = math::mulu64(a, b); 450 const res = lo; 451 const overflow = hi != 0; 452 return (res, overflow); 453 }; 454 455 @test fn mulu64() void = { 456 const (res, overflow) = mulu64(4294967295, 4294967295); 457 assert(res == 18446744065119617025); 458 assert(!overflow); 459 const (res, overflow) = mulu64(4294967296, 4294967296); 460 assert(res == 0); 461 assert(overflow); 462 }; 463 464 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 465 export fn mulu(a: uint, b: uint) (uint, bool) = { 466 if (size(uint) == 4) { 467 const ret = mulu32(a: u32, b: u32); 468 return (ret.0, ret.1); 469 } else { 470 const ret = mulu64(a, b); 471 return (ret.0: uint, ret.1); 472 }; 473 }; 474 475 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 476 export fn mulz(a: size, b: size) (size, bool) = { 477 if (size(size) == 4) { 478 const ret = mulu32(a: u32, b: u32); 479 return (ret.0, ret.1); 480 } else { 481 const ret = mulu64(a, b); 482 return (ret.0: size, ret.1); 483 }; 484 };