hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };