checked.ha (10381B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use math; 5 6 // Adds 'a' and 'b', returning the result and whether overflow occurred. 7 export fn addi8(a: i8, b: i8) (i8, bool) = { 8 const res = a + b; 9 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 10 return (res, overflow); 11 }; 12 13 @test fn addi8() void = { 14 const (res, overflow) = addi8(100, 20); 15 assert(res == 120); 16 assert(!overflow); 17 const (res, overflow) = addi8(100, 50); 18 assert(res == -106); 19 assert(overflow); 20 }; 21 22 // Adds 'a' and 'b', returning the result and whether overflow occurred. 23 export fn addi16(a: i16, b: i16) (i16, bool) = { 24 const res = a + b; 25 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 26 return (res, overflow); 27 }; 28 29 @test fn addi16() void = { 30 const (res, overflow) = addi16(32700, 60); 31 assert(res == 32760); 32 assert(!overflow); 33 const (res, overflow) = addi16(32700, 100); 34 assert(res == -32736); 35 assert(overflow); 36 }; 37 38 // Adds 'a' and 'b', returning the result and whether overflow occurred. 39 export fn addi32(a: i32, b: i32) (i32, bool) = { 40 const res = a + b; 41 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 42 return (res, overflow); 43 }; 44 45 @test fn addi32() void = { 46 const (res, overflow) = addi32(2147483600, 40); 47 assert(res == 2147483640); 48 assert(!overflow); 49 const (res, overflow) = addi32(2147483600, 100); 50 assert(res == -2147483596); 51 assert(overflow); 52 }; 53 54 // Adds 'a' and 'b', returning the result and whether overflow occurred. 55 export fn addi64(a: i64, b: i64) (i64, bool) = { 56 const res = a + b; 57 const overflow = a < 0 == b < 0 && a < 0 != res < 0; 58 return (res, overflow); 59 }; 60 61 @test fn addi64() void = { 62 const (res, overflow) = addi64(9223372036854775800, 5); 63 assert(res == 9223372036854775805); 64 assert(!overflow); 65 const (res, overflow) = addi64(9223372036854775800, 10); 66 assert(res == -9223372036854775806); 67 assert(overflow); 68 }; 69 70 // Adds 'a' and 'b', returning the result and whether overflow occurred. 71 export fn addu8(a: u8, b: u8) (u8, bool) = { 72 const res = a + b; 73 const overflow = res < a; 74 return (res, overflow); 75 }; 76 77 @test fn addu8() void = { 78 const (res, overflow) = addu8(200, 50); 79 assert(res == 250); 80 assert(!overflow); 81 const (res, overflow) = addu8(200, 100); 82 assert(res == 44); 83 assert(overflow); 84 }; 85 86 // Adds 'a' and 'b', returning the result and whether overflow occurred. 87 export fn addu16(a: u16, b: u16) (u16, bool) = { 88 const res = a + b; 89 const overflow = res < a; 90 return (res, overflow); 91 }; 92 93 @test fn addu16() void = { 94 const (res, overflow) = addu16(65500, 30); 95 assert(res == 65530); 96 assert(!overflow); 97 const (res, overflow) = addu16(65500, 50); 98 assert(res == 14); 99 assert(overflow); 100 }; 101 102 // Adds 'a' and 'b', returning the result and whether overflow occurred. 103 export fn addu32(a: u32, b: u32) (u32, bool) = { 104 const res = a + b; 105 const overflow = res < a; 106 return (res, overflow); 107 }; 108 109 @test fn addu32() void = { 110 const (res, overflow) = addu32(4294967200, 90); 111 assert(res == 4294967290); 112 assert(!overflow); 113 const (res, overflow) = addu32(4294967200, 100); 114 assert(res == 4); 115 assert(overflow); 116 }; 117 118 // Adds 'a' and 'b', returning the result and whether overflow occurred. 119 export fn addu64(a: u64, b: u64) (u64, bool) = { 120 const res = a + b; 121 const overflow = res < a; 122 return (res, overflow); 123 }; 124 125 @test fn addu64() void = { 126 const (res, overflow) = addu64(18446744073709551600, 10); 127 assert(res == 18446744073709551610); 128 assert(!overflow); 129 const (res, overflow) = addu64(18446744073709551610, 50); 130 assert(res == 44); 131 assert(overflow); 132 }; 133 134 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 135 export fn subi8(a: i8, b: i8) (i8, bool) = addi8(a, -b); 136 137 @test fn subi8() void = { 138 const (res, overflow) = subi8(-100, 20); 139 assert(res == -120); 140 assert(!overflow); 141 const (res, overflow) = subi8(-100, 50); 142 assert(res == 106); 143 assert(overflow); 144 }; 145 146 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 147 export fn subi16(a: i16, b: i16) (i16, bool) = addi16(a, -b); 148 149 @test fn subi16() void = { 150 const (res, overflow) = subi16(-32700, 60); 151 assert(res == -32760); 152 assert(!overflow); 153 const (res, overflow) = subi16(-32700, 100); 154 assert(res == 32736); 155 assert(overflow); 156 }; 157 158 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 159 export fn subi32(a: i32, b: i32) (i32, bool) = addi32(a, -b); 160 161 @test fn subi32() void = { 162 const (res, overflow) = subi32(-2147483600, 40); 163 assert(res == -2147483640); 164 assert(!overflow); 165 const (res, overflow) = subi32(-2147483600, 100); 166 assert(res == 2147483596); 167 assert(overflow); 168 }; 169 170 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 171 export fn subi64(a: i64, b: i64) (i64, bool) = addi64(a, -b); 172 173 @test fn subi64() void = { 174 const (res, overflow) = subi64(-9223372036854775800, 5); 175 assert(res == -9223372036854775805); 176 assert(!overflow); 177 const (res, overflow) = subi64(-9223372036854775800, 10); 178 assert(res == 9223372036854775806); 179 assert(overflow); 180 }; 181 182 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 183 export fn subu8(a: u8, b: u8) (u8, bool) = { 184 const res = a - b; 185 const overflow = res > a; 186 return (res, overflow); 187 }; 188 189 @test fn subu8() void = { 190 const (res, overflow) = subu8(250, 50); 191 assert(res == 200); 192 assert(!overflow); 193 const (res, overflow) = subu8(44, 100); 194 assert(res == 200); 195 assert(overflow); 196 }; 197 198 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 199 export fn subu16(a: u16, b: u16) (u16, bool) = { 200 const res = a - b; 201 const overflow = res > a; 202 return (res, overflow); 203 }; 204 205 @test fn subu16() void = { 206 const (res, overflow) = subu16(65530, 30); 207 assert(res == 65500); 208 assert(!overflow); 209 const (res, overflow) = subu16(14, 50); 210 assert(res == 65500); 211 assert(overflow); 212 }; 213 214 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 215 export fn subu32(a: u32, b: u32) (u32, bool) = { 216 const res = a - b; 217 const overflow = res > a; 218 return (res, overflow); 219 }; 220 221 @test fn subu32() void = { 222 const (res, overflow) = subu32(4294967290, 90); 223 assert(res == 4294967200); 224 assert(!overflow); 225 const (res, overflow) = subu32(4, 100); 226 assert(res == 4294967200); 227 assert(overflow); 228 }; 229 230 // Subtracts 'b' from 'a', returning the result and whether overflow occurred. 231 export fn subu64(a: u64, b: u64) (u64, bool) = { 232 const res = a - b; 233 const overflow = res > a; 234 return (res, overflow); 235 }; 236 237 @test fn subu64() void = { 238 const (res, overflow) = subu64(18446744073709551610, 10); 239 assert(res == 18446744073709551600); 240 assert(!overflow); 241 const (res, overflow) = subu64(44, 50); 242 assert(res == 18446744073709551610); 243 assert(overflow); 244 }; 245 246 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 247 export fn muli8(a: i8, b: i8) (i8, bool) = { 248 const fullres = a: i16 * b: i16; 249 const res = fullres: i8; 250 const overflow = res != fullres; 251 return (res, overflow); 252 }; 253 254 @test fn muli8() void = { 255 const (res, overflow) = muli8(11, 11); 256 assert(res == 121); 257 assert(!overflow); 258 const (res, overflow) = muli8(12, 12); 259 assert(res == -112); 260 assert(overflow); 261 }; 262 263 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 264 export fn muli16(a: i16, b: i16) (i16, bool) = { 265 const fullres = a: i32 * b: i32; 266 const res = fullres: i16; 267 const overflow = res != fullres; 268 return (res, overflow); 269 }; 270 271 @test fn muli16() void = { 272 const (res, overflow) = muli16(181, 181); 273 assert(res == 32761); 274 assert(!overflow); 275 const (res, overflow) = muli16(182, 182); 276 assert(res == -32412); 277 assert(overflow); 278 }; 279 280 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 281 export fn muli32(a: i32, b: i32) (i32, bool) = { 282 const fullres = a: i64 * b: i64; 283 const res = fullres: i32; 284 const overflow = res != fullres; 285 return (res, overflow); 286 }; 287 288 @test fn muli32() void = { 289 const (res, overflow) = muli32(46340, 46340); 290 assert(res == 2147395600); 291 assert(!overflow); 292 const (res, overflow) = muli32(46341, 46341); 293 assert(res == -2147479015); 294 assert(overflow); 295 }; 296 297 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 298 export fn muli64(a: i64, b: i64) (i64, bool) = { 299 const (hi, lo) = math::mulu64(math::absi64(a), math::absi64(b)); 300 const res = a * b; 301 const overflow = hi != 0 || lo & (1 << 63) != 0; 302 return (res, overflow); 303 }; 304 305 @test fn muli64() void = { 306 const (res, overflow) = muli64(3037000499, 3037000499); 307 assert(res == 9223372030926249001); 308 assert(!overflow); 309 const (res, overflow) = muli64(3037000500, 3037000500); 310 assert(res == -9223372036709301616); 311 assert(overflow); 312 }; 313 314 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 315 export fn mulu8(a: u8, b: u8) (u8, bool) = { 316 const fullres = a: u16 * b: u16; 317 const res = fullres: u8; 318 const overflow = res != fullres; 319 return (res, overflow); 320 }; 321 322 @test fn mulu8() void = { 323 const (res, overflow) = mulu8(15, 15); 324 assert(res == 225); 325 assert(!overflow); 326 const (res, overflow) = mulu8(16, 16); 327 assert(res == 0); 328 assert(overflow); 329 }; 330 331 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 332 export fn mulu16(a: u16, b: u16) (u16, bool) = { 333 const fullres = a: u32 * b: u32; 334 const res = fullres: u16; 335 const overflow = res != fullres; 336 return (res, overflow); 337 }; 338 339 @test fn mulu16() void = { 340 const (res, overflow) = mulu16(255, 255); 341 assert(res == 65025); 342 assert(!overflow); 343 const (res, overflow) = mulu16(256, 256); 344 assert(res == 0); 345 assert(overflow); 346 }; 347 348 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 349 export fn mulu32(a: u32, b: u32) (u32, bool) = { 350 const fullres = a: u64 * b: u64; 351 const res = fullres: u32; 352 const overflow = res != fullres; 353 return (res, overflow); 354 }; 355 356 @test fn mulu32() void = { 357 const (res, overflow) = mulu32(65535, 65535); 358 assert(res == 4294836225); 359 assert(!overflow); 360 const (res, overflow) = mulu32(65536, 65536); 361 assert(res == 0); 362 assert(overflow); 363 }; 364 365 // Multiplies 'a' and 'b' returning the result and whether overflow occurred. 366 export fn mulu64(a: u64, b: u64) (u64, bool) = { 367 const (hi, lo) = math::mulu64(a, b); 368 const res = lo; 369 const overflow = hi != 0; 370 return (res, overflow); 371 }; 372 373 @test fn mulu64() void = { 374 const (res, overflow) = mulu64(4294967295, 4294967295); 375 assert(res == 18446744065119617025); 376 assert(!overflow); 377 const (res, overflow) = mulu64(4294967296, 4294967296); 378 assert(res == 0); 379 assert(overflow); 380 };