/* YOUR FILE-HEADER COMMENT HERE */ #define _POSIX_C_SOURCE 200112L #include #include #include #include /** * Given a 16-bit binary value, break down its IEEE-754 half-precision * floating point representation. * * Display the sign bit, un-biased exponent, and significand * (including the leading implied bit). If the value is special, * display what kind of value it is; for infinity and NaN, the leading * implied bit is a don't care. * * @param[in] val 16-bit floating point value to analyze. * @return true if @a val is a normal value, false if it is special */ static bool half_float_parse(uint16_t val) { _Float16 f = *((_Float16 *) & (val)); printf("For the bit pattern 0x%04x (half float value: %g):\n", val, (float)f); bool is_normal = true; /* PART 1: YOUR CODE HERE */ return is_normal; } /** * Perform 16-bit unsigned integer multiplication of @a i1 and @a i2, * writing the product to @a upper and @a lower. * * You have your choice of whatever algorithm to implement. If you * choose to use Booth's algorithm, please make a note at the top of * this file. * * SPECIAL RESTRICTION: you may only use addition, subtraction, * shifts, rotate, bitmasks, compare, and branch operations. You * may not use any built-in multiplication or * division instructions for this part. * * @param[in] i1 Multiplicand * @param[in] i2 Multiplier * @param[out] upper Upper 16 bits of product * @param[out] lower Lower 16 bits of product */ extern void uint16_mult(uint16_t i1, uint16_t i2, uint16_t * upper, uint16_t * lower); /** * Perform floating-point multiplication of @a f1 and @a f2, then * return the product. * * You have your choice of whatever algorithm to implement. If you * choose to use Booth's algorithm, please make a note at the top of * this file. * * Round the significand to 10 bits (excluding implied leading * one). Assume the product will be normal, not infinity nor denormal. * * SPECIAL RESTRICTION: you may only use addition, subtraction, * shifts, rotate, bitmasks, compare, and branch operations. You * may not use the real multiplication or division * operator. You MUST use your uint16_mult() * function. * * @param[in] f1 Multiplicand, a normal half floating point value * @param[in] f2 Multiplier, a normal half floating point value * @return Product of @f1 times @f2, represented as half floating * point */ static _Float16 half_float_mult(_Float16 f1, _Float16 f2) { uint16_t val1 = *((uint16_t *) & f1); uint16_t val2 = *((uint16_t *) & f2); unsigned ret_sign = 0; unsigned ret_exp = 0; uint16_t product_upper = 0; uint16_t product_lower = 0; /* PART 3: YOUR CODE HERE */ uint16_t retval = 0; uint16_t ret_significand = ((product_upper & 0xf) << 6) | ((product_lower & 0xfc00) >> 10); if (product_lower & 0x0200) { /* round up */ ret_significand = (ret_significand + 1) & 0xffff; } retval |= (ret_sign << 15); retval |= (ret_exp & 0x1f) << 10; retval |= ret_significand; return *((_Float16 *) & retval); } int main(int argc, char *argv[]) { if (argc < 3) { fprintf(stderr, "Need at least two arguments\n"); exit(EXIT_FAILURE); } char *endptr; unsigned long long arg1 = strtoull(argv[1], &endptr, 0); if (!(*(argv[1])) || *endptr) { fprintf(stderr, "Argument 1 not a number: %s\n", argv[1]); exit(EXIT_FAILURE); } unsigned long long arg2 = strtoull(argv[2], &endptr, 0); if (!*(argv[2]) || *endptr) { fprintf(stderr, "Argument 2 not a number: %s\n", argv[2]); exit(EXIT_FAILURE); } uint16_t i1 = (uint16_t) arg1; uint16_t i2 = (uint16_t) arg2; bool is_normal1 = half_float_parse(i1); bool is_normal2 = half_float_parse(i2); printf("Part 2: multiplying %u and %u:\n", i1, i2); uint32_t correct_product = i1 * i2; printf(" Correct product: 0x%08x (uint32_t value: %u)\n", correct_product, correct_product); uint16_t part2_product_upper = 0; uint16_t part2_product_lower = 0; uint16_mult(i1, i2, &part2_product_upper, &part2_product_lower); uint32_t part2_product = (part2_product_upper << 16) | (part2_product_lower & 0xffff); printf(" Part 2 product: 0x%04x%04x (uint32_t value: %u)\n", part2_product_upper, part2_product_lower, part2_product); if (is_normal1 && is_normal2) { _Float16 f1 = *((_Float16 *) & (arg1)); _Float16 f2 = *((_Float16 *) & (arg2)); _Float16 correct_product = f1 * f2; printf("Part 3: multiplying %g and %g:\n", (float)f1, (float)f2); printf(" Correct product: 0x%04x (value: %g)\n", *((uint16_t *) & (correct_product)), (float)correct_product); _Float16 calc_product = half_float_mult(f1, f2); printf(" Part 3 product: 0x%04x (half float value: %g)\n", *((uint16_t *) & (calc_product)), (float)calc_product); } return 0; }