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