C Programming - Floating point numbers The ifloat .h file includes the Instructi
ID: 3743744 • Letter: C
Question
C Programming - Floating point numbers
The ifloat.h file includes the Instructions/ declarations
Code to be completed is in ifloat.c do not modify ifloat.h
Below is the iFloat.c file
#include "iFloat.h"
/** @file iFloat.c
* @brief You will modify this file and implement nine functions
* @details Your implementation of the functions defined in iFloat.h.
* You may add other function if you find it helpful. Added function
* should be declared static to indicate they are only used
* within this file.
*
*/
/* declaration for useful function contained in testFloat.c */
const char* getBinary (iFloat_t value);
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatGetSign (iFloat_t x) {
return 0; /* implement this */
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatGetExp (iFloat_t x) {
return 0; /* implement this */
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatGetVal (iFloat_t x) {
return 0;
}
/** @todo Implement based on documentation contained in iFloat.h */
void floatGetAll(iFloat_t x, iFloat_t* sign, iFloat_t*exp, iFloat_t* val) {
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatLeftMost1 (iFloat_t bits) {
return -1;
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatAbs (iFloat_t x) {
return 0;
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatNegate (iFloat_t x) {
return 0;
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatAdd (iFloat_t x, iFloat_t y) {
debug("%s: bits of x (IEEE 754)", getBinary(x)); // example only
debug("%s: bits of y (IEEE 754)", getBinary(y)); // example only
return 0;
}
/** @todo Implement based on documentation contained in iFloat.h */
iFloat_t floatSub (iFloat_t x, iFloat_t y) {
return 0;
}
---------------------
#ifndef __IFLOAT_H__
#define __IFLOAT_H__
/*
* iFloat.h - header for simple floating point functions.
*
/** @file iFloat.h
* @brief Defines interface of iFloat.c functions (do not modify)
* @details This file defines the interface to a C file iFloat.c that
* you will complete. You will learn how to do floating point arithmetic
* without using any float variables. Rather you will
* perform the operations by using the sign, exponent, and digit fields
* as defined in the
* IEEE Floating
* Point Standard.
*
* Everything in a computer is stored as a series of 0/1's. When you use an
* int to type a value, you are telling the compiler (and
* ultimately the CPU) to treat the 0/1's as a two's complement number. When
* you use float, the 0/1's represent a floating point number.
* When an addition is performed, the computer knows whether to use the
* integer or floating point add instruction. The two instructions do different
* things to the 0/1's.
In this assignment, you are doing floating point
* operations without using floating point instructions. You are
* directly doing the bit manipulations necessary to complete the add. Since
* iFloat_t is an integral type, the compiler will generate integer
* instructions. The iFloat_t is to remind you (the programmer),
* that although the computer is going to treat all values as integers, you
* know it is really 3 values (sign, exponent, mantissa) packed into a single
* integer number. Your responsibility is to unpack the three pieces, do the
* operations necessary to complete the operation, then put the three pieces
* back together.
*/
#ifdef HALF
typedef short iFloat_t;
#define BITS 16
#define BITS_EXP 5
#define BITS_MANT 10
#define EXP_BIAS 15
#else
typedef int iFloat_t;
#define BITS 32
#define BITS_EXP 8
#define BITS_MANT 23
#define EXP_BIAS 127
#endif
/** Extract the sign of the argument.
* @param x the integer containing an IEEE floating point value
* @return 0 if the value is 0 or positive, 1 if it is negative
*/
iFloat_t floatGetSign (iFloat_t x);
/** Extract the exponent of the argument.
* @param x the integer containing an IEEE floating point value
* @return the biased exponent of the argument
*/
iFloat_t floatGetExp (iFloat_t x);
/** Extract the value of the argument. The value is the mantissa with the
* implicit 1 made explicit and adjusted for the sign of the argument. Please
* refer to the floating point addition example (step 1) in the instructions for
* an example on how the value is extracted. Basically, you'll have to do three
* things: 1) extract the mantissa; 2) set the implicit 1 in the extracted
* mantissa; 3) if the sign of the argument is negative, return the 2's complement
* of the mantissa from step (2). Otherwise, return it as-is. You may want to use
* the getField function from R3.
* @param x the integer containing an IEEE floating point value
* @return the bits representing the value. If x represents 0.0, you should still
* set the implicit 1 in the extracted mantissa.
*/
iFloat_t floatGetVal (iFloat_t x);
/** Get the sign, exponent, and value in a single call.
* @param x the integer containing an IEEE floating point value
* @param sign pointer to location where the sign will be stored
* @param exp pointer to location where the exponent will be stored
* @param val pointer to location where the value will be stored
*/
void floatGetAll(iFloat_t x, iFloat_t* sign, iFloat_t*exp, iFloat_t* val);
/** Obtain the position of the leftmost 1 in the argument's bits.
* @param bits the integer
* @return -1 if the value is 0, otherwise the position (0 to 15) of the
* leftmost 1 bit. In a binary number, the positions are numbered from right to
* left with the rightmost position being 0.
*/
iFloat_t floatLeftMost1 (iFloat_t bits);
/** Absolute value of the argument. This can be done with a simple bit
* manipulation operation. No conditionals are required.
* @param x the integer containing an IEEE floating point value
* @return the absolute value of the parameter
*/
iFloat_t floatAbs (iFloat_t x);
/** Negate the argument. This can be done with a simple bit manipulation
* function. No conditionals are required. This is NOT the bitwise negation
* of the argument. As an example, if the argument represents 2.25, this function
* should return the IEEE bit pattern for -2.25.
* @param x the integer containing an IEEE floating point value
* @return the negation of the value. Note that the negation of 0.0 is 0.0 (not
* -0.0).
*/
iFloat_t floatNegate (iFloat_t x);
/** Add two floating point values.
* @param x an integer containing an IEEE floating point value
* @param y an integer containing an IEEE floating point value
* @return x + y. Your code needs to account for a value of 0.0, but no other
* special cases (e.g. infinities).
*/
iFloat_t floatAdd (iFloat_t x, iFloat_t y);
/** Subtract two floating point values.
* @param x an integer containing an IEEE floating point value
* @param y an integer containing an IEEE floating point value
* @return x - y. Your code needs to account for a value of 0.0, but no other
* special cases (e.g. infinities).
*/
iFloat_t floatSub (iFloat_t x, iFloat_t y);
#endif
Explanation / Answer
testFloat.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include "Debug.h"
#include "convert.h"
#include "iFloat.h"
const char* getBinaryMSB (int value, int msb) {
static char bits[48];
int i = 0;
while (msb >= 0) {
bits[i++] = ((value & (1 << msb)) ? '1' : '0');
if (msb && ((msb & 0x3) == 0))
bits[i++] = '-';
msb--;
}
bits[i] = ''; // terminate string
return bits;
}
const char* getBinary (iFloat_t value) {
return getBinaryMSB(value, BITS-1);
}
/** Print a usage statement, then exit the program returning a non zero
* value, the Linux convention indicating an error
*/
static void usage() {
puts("usage: testFloat [-debug] abs FPvalue");
puts(" testFloat [-debug] all FPvalue");
puts(" testFloat [-debug] add FPvalue1 FPvalue2");
puts(" testFloat [-debug] bin FPvalue");
puts(" testFloat [-debug] exp FPvalue");
puts(" testFloat [-debug] lm1 Intvalue");
puts(" testFloat [-debug] neg FPvalue");
puts(" testFloat [-debug] sign FPvalue");
puts(" testFloat [-debug] sub FPvalue1 FPvalue2");
puts(" testFloat [-debug] val FPvalue ");
exit(1);
}
int main (int argc, const char* argv[]) {
iFloat_t x, y;
debugInit(&argc, argv);
if (argc < 3) {
usage();
}
const char* op = argv[1];
x = toiFloat(argv[2]);
if (argc > 3)
y = toiFloat(argv[3]);
if ((strcmp(op, "abs") == 0) && (argc == 3)) {
printf("abs(%s) --> %f ", argv[2], fromiFloat(floatAbs(x)));
}
else if ((strcmp(op, "all") == 0) && (argc == 3)) {
iFloat_t sign, exp, val;
floatGetAll(x, &sign, &exp, &val);
printf("sign: %d exp: %d val: %s ", sign, exp, getBinary(val));
}
else if ((strcmp(op, "add") == 0) && (argc == 4)) {
printf("%s + %s --> %f ", argv[2], argv[3], fromiFloat(floatAdd(x, y)));
}
else if ((strcmp(op, "bin") == 0) && (argc == 3)) {
printf("dec: %d hex: 0x%X bin: %s ", x, x, getBinary(x));
}
else if ((strcmp(op, "exp") == 0) && (argc == 3)) {
printf("exp %s --> %d ", argv[2], floatGetExp(x));
}
else if ((strcmp(op, "lm1") == 0) && (argc == 3)) {
printf("%d ", floatLeftMost1(x));
}
else if ((strcmp(op, "neg") == 0) && (argc == 3)) {
printf("neg(%s) --> %f ", argv[2], fromiFloat(floatNegate(x)));
}
else if ((strcmp(op, "sign") == 0) && (argc == 3)) {
printf("sign(%s) --> %d ", argv[2], floatGetSign(x));
}
else if ((strcmp(op, "sub") == 0) && (argc == 4)) {
printf("%s - %s --> %f ", argv[2], argv[3], fromiFloat(floatSub(x, y)));
}
else if ((strcmp(op, "val") == 0) && (argc == 3)) {
printf("val(%s) --> %s ", argv[2], getBinary(floatGetVal(x)));
}
else
usage();
return 0;
}
iFloat.h
#ifndef __IFLOAT_H__
#define __IFLOAT_H__
#ifdef HALF
typedef short iFloat_t;
#define BITS 16
#define BITS_EXP 5
#define BITS_MANT 10
#define EXP_BIAS 15
#else
typedef int iFloat_t;
#define BITS 32
#define BITS_EXP 8
#define BITS_MANT 23
#define EXP_BIAS 127
#endif
/** Extract the sign of the argument.
* @param x the integer containing an IEEE floating point value
* @return 0 if the value is 0 or positive, 1 if it is negative
*/
iFloat_t floatGetSign (iFloat_t x);
/** Extract the exponent of the argument.
* @param x the integer containing an IEEE floating point value
* @return the biased exponent of the argument
*/
iFloat_t floatGetExp (iFloat_t x);
iFloat_t floatGetVal (iFloat_t x);
void floatGetAll(iFloat_t x, iFloat_t* sign, iFloat_t*exp, iFloat_t* val);
iFloat_t floatLeftMost1 (iFloat_t bits);
iFloat_t floatAbs (iFloat_t x);
iFloat_t floatNegate (iFloat_t x);
iFloat_t floatAdd (iFloat_t x, iFloat_t y);
iFloat_t floatSub (iFloat_t x, iFloat_t y);
#endif
iFloat.c
#include "Debug.h"
#include "iFloat.h"
/* declaration for useful function contained in testFloat.c */
const char* getBinary (iFloat_t value);
iFloat_t floatGetSign (iFloat_t x) {
return ((x & 0x8000) >> 15);
}
iFloat_t floatGetExp (iFloat_t x) {
return ((x & 0x7C00) >> 10);
}
iFloat_t floatGetVal (iFloat_t x) {
int odd = floatGetSign(x);
int mantissa = ((x | 0x0400) & 0x07FF);
if(!odd){
return mantissa;
}
return (~mantissa + 1);
}
void floatGetAll(iFloat_t x, iFloat_t* sign, iFloat_t*exp, iFloat_t* val) {
*sign = floatGetSign(x);
*exp = floatGetExp(x);
*val = floatGetVal(x);
}
iFloat_t floatLeftMost1 (iFloat_t bits) {
for(int i = 15; i > 0; i--){
int bitValue = (bits & (1 << i)) != 0;
if(bitValue == 1){
return i;
}
}
return -1;
}
iFloat_t floatAbs (iFloat_t x) {
return (x & 0x7FFF);
}
iFloat_t floatNegate (iFloat_t x) {
if(x > 0 || x < 0){
return x ^ 0x8000;
}else{
return x;
}
}
iFloat_t floatAdd (iFloat_t x, iFloat_t y) {
//check for 0's
if(x == 0 || y == 0){
if(x != 0){
return x;
}
if(y != 0){
return y;
}
else{
return 0;
}
}
iFloat_t signX = -1, expX = -1, valX = -1;
iFloat_t signY = -1, expY = -1, valY = -1;
floatGetAll(x, &signX, &expX, &valX);
floatGetAll(y, &signY, &expY, &valY);
//Normalize exponents so they equal eachother
if(expX > expY){
int diff = expX - expY;
expY += diff;
valY = valY >> diff;
}
else if(expX < expY){
int diff = expY - expX;
expX += diff;
valX = valX >> diff;
}
iFloat_t expResult = expY;
iFloat_t valResult = valX + valY;
iFloat_t signResult = floatGetSign(valResult);
//Make sure val of result is positive
iFloat_t magResult = valResult;
if(signResult == 1){//negative number
magResult = ~valResult + 1;
}
//Make sure only one bit to the left of decimal point
if(floatLeftMost1(magResult) < 10){
int pointDiff = 10 - floatLeftMost1(magResult);
magResult = magResult << pointDiff;
expResult -= pointDiff;
}
if(floatLeftMost1(magResult) > 10){
int pointDiff = floatLeftMost1(magResult) - 10;
magResult = magResult >> pointDiff;
expResult += pointDiff;
}
magResult = magResult ^ 0x0400;//get rid of explicit 1
iFloat_t ans = (signResult << 15) | (expResult << 10) | (magResult);
return ans;
}
iFloat_t floatSub (iFloat_t x, iFloat_t y) {
return floatAdd(x, floatNegate(y));
}
convert.h
#ifndef __CONVERT_H__
#define __CONVERT_H__
#include "iFloat.h"
iFloat_t toiFloat (const char* str);
float fromiFloat (iFloat_t x);
#endif
Debug.h
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
void debugInit(int* argc, const char* argv[]);
/** Send the debug output to a file
* @param fileName name of file to write debug output to
*/
void debugToFile(const char* fileName);
/** Close the external file and reset <tt>debugFile</tt> to <tt>stderr</tt>
*/
void debugClose(void);
/** Control how much debug output is produced. Higher values produce more
* output. See the use in <tt>lDebug()</tt>.
*/
extern int debugLevel;
/** The file where debug output is written. Defaults to <tt>stderr</tt>.
* <tt>debugToFile()</tt> allows output to any file.
*/
extern FILE* debugFile;
#ifdef DEBUG
#define DEBUG_ENABLED 1 // debug code available at runtime
#else
#define DEBUG_ENABLED 0 // all debug code optimized out
#endif
/** Print the file name, line number, function name and "HERE" */
#define HERE debug("HERE")
/** Expand a name into a string and a value
* @param name name of variable
*/
#define debugV(name) #name,(name)
/** Output the name and value of a single variable
* @param fmt the formatting string (<b>MUST</b> be a literal)
* @param name name of the variable to print
*/
#define vDebug(fmt, name) debug("%s=(" fmt ")" , debugV(name))
/** Simple alias for <tt>lDebug()</tt> */
#define debug(fmt, ...) lDebug(1, fmt, ##__VA_ARGS__)
#define lDebug(level, fmt, ...)
do {
if (DEBUG_ENABLED && (debugLevel >= level))
fprintf((debugFile ? debugFile : stderr), "DEBUG %s[%d] %s() " fmt " ",
__FILE__, __LINE__, __func__, ##__VA_ARGS__);
} while(0)
#ifdef __cplusplus
}
#endif
#endif
Debug.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Debug.h"
int debugLevel = 0;
FILE* debugFile = 0;
static const char* prefix = "-debug";
void debugInit (int* argc, const char* argv[]) {
debugFile = stderr;
if (*argc > 1) {
const char* arg1 = argv[1];
size_t len = strlen(prefix);
if (strncmp(arg1, prefix, len) == 0) {
debugLevel = 1;
if (strlen(arg1) > len)
debugLevel = atoi(arg1 + len);
(*argc)--; // decrement number of arguments
for (int i = 1; i < *argc; i++) // remove first argument
argv[i] = argv[i+1];
}
}
}
void debugToFile (const char* fileName) {
debugClose();
FILE* f = fopen(fileName, "w"); // "w+" ?
if (f)
debugFile = f;
}
void debugClose(void) {
if (debugFile && (debugFile != stderr)) {
fclose(debugFile);
debugFile = stderr;
}
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.