I am trying to write a C program to print the filesizes in human readable format (i.e, in KB, MB, GB, etc). The input is the filesize in bytes. The catch is that this is to be done using only system calls and NO library calls.
I have already written a function that converts a positive integer into a string and then prints it using write() system call. I am clueless as to how to print decimal values using write() as the filesize after conversion(in KB or MB or GB) could be decimals.(For Ex: 4.0K, 5.6G etc).
Also, is it possible to limit precision to some fixed length (say 2 decimal places) ??
For a lot of cases, you can convert your floats the same way you do with integers. First convert the integer part by casting your float to int and converting that to string. Then append the decimal point, subtract the integer from your original float, multiply by your required precision and do the same (with leading zeros if required).
Conceptually you could do something like that:
int integerPart = myFloat;
int decimalPart = (myFloat - integerPart) * 1000; // for three decimal places
char* stringRep = intToStringNoLeadingZeros(integerPart);
appendChar(stringRep, '.');
appendIntToStringWithLeadingZeros(stringRep, decimalPart);
This does not work with floats that are larger than the largest possible integer and it will lose precision if you need lots of decimal places. But for the common case this is a quick way to do it. You would have to write code that interpretes the floating point format directly if you want it to work for alle cases, but I imagine that to be a lot more work.
I think that this is your solution:
#include <unistd.h>
void printInt(int n) {
char c;
if (!n)
return ;
printInt(n/10);
c = n % 10 + '0';
write(1, &c, 1);
}
void _printInt(int n) {
if (!n)
write(1, "0", 1);
else
printInt(n);
}
void _printD(double n, int K) {
_printInt((int)n);
n -= (int)n;
if (!n && !K)
return ;
write(1, ".", 1);
while ((!n && K) || K) {
_printInt((int)(n*10));
n=n*10-((int)(n*10));
K--;
}
}
int main() {
_printD(10.543, 2);
return 0;
}
if you need some advice just say!
void printNum(unsigned n){
char nums[4];
int i;
if(n == 0)
write(1, "0", 1);
for(i=4; n ;){
nums[--i] = '0' + n % 10;
n /= 10;
}
write(1, &nums[i], 4 - i);
}
void printStr(const char *s){
while(*s)
write(1, s++, 1);
}
void printSizeWithUnit(unsigned long long n){
static char *unit[] = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
unsigned long long v = n;
int u_no = 0;
while(n >= 1024){
v = (n * 10+512) / 1024;
n /= 1024;
++u_no;
}
if(v>=1000){
v = (n * 10+512) / 1024;
++u_no;
}
if(u_no==0){
printNum((unsigned)v);
printStr(unit[u_no]);
printStr("\n");
} else {
printNum((unsigned)v/10);
printStr(".");
printNum((unsigned)v%10);
printStr(unit[u_no]);
printStr("\n");
}
}
int main(void){
printSizeWithUnit(777ULL);
printSizeWithUnit((unsigned long long)(5.56*1024*1024));
printSizeWithUnit(1024*777ULL);
printSizeWithUnit(1024*1024*777ULL);
return 0;
}
Related
I would like to convert a very long (arbitrary length, possibly 1000 characters long; university assignment) string into binary. How should I approach this problem? I have thought about it for a while, but I just can't seem to think of anything viable.
The string will be passed to me as const char *str. I want to read the number, which will be in Base 10, and convert it into binary.
Should I read certain number of least significant numbers and store them in unsigned long long int, and then work from there? Is there a better solution? I don't know how the method I suggested would pan out. I wanted to know if there's a better/easier way to do it.
Thank you.
Assuming your input is too large for the biggest integer type, you have to convert it to a unlimited size integer. For this purpose you can use gmplib. If you are not allowed to use external libraries, you can use a different approach:
is your string divisible by two (look at the last digit)?
if yes, write 0 to left side of your output
else, write 1 to left side of your output
divide the string by 2 (every digit)
repeat while string is not filled with 0
I am going to edit this answer, as soon as I wrote the code.
Here you go:
#include<stdbool.h>
#include<stdlib.h>
#include<memory.h>
#include<stdio.h>
typedef struct char_queue {
unsigned int len;
unsigned int capacity;
char* data;
} char_queue;
char_queue init_char_queue() {
return (char_queue) {
0,
4096,
malloc(4096)
};
}
void enqueue(char_queue* queue, char val) {
if (queue->len == queue->capacity) {
char* new_queue_data = malloc(queue->capacity + 4096);
memmove(new_queue_data, queue->data, queue->capacity);
free(queue->data);
queue->data = new_queue_data;
}
queue->len++;
queue->data[queue->capacity - queue->len] = val;
}
char* queue_get_arr(char_queue* queue) {
char* output = malloc(queue->len);
memcpy(output, &queue->data[queue->capacity - queue->len], queue->len);
return output;
}
void free_char_queue(char_queue* queue) {
if (queue->data) free(queue->data);
}
void convert_to_digit_arr(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
input[i] = input[i] - '0'; // '5' - '0' = 5
}
}
bool is_null(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
if (input[i] != 0) return false;
}
return true;
}
bool divisible_by_two(char* digit_arr, unsigned int len) {
return digit_arr[len - 1] % 2 == 0;
}
void divide_by_two(char* digit_arr, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
bool is_odd = digit_arr[i] % 2 == 1;
digit_arr[i] /= 2;
if (is_odd && i + 1 < len) { // and is not last (right) digit
digit_arr[i + 1] += 10;
}
}
}
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
unsigned int input_len = strlen(argv[i]);
char* input = malloc(input_len + 1);
strcpy(input, argv[i]);
convert_to_digit_arr(input, input_len);
char_queue queue = init_char_queue();
enqueue(&queue, 0); // null terminator to use the queue content as a string
while (!is_null(input, input_len)) {
enqueue(&queue, divisible_by_two(input, input_len) ? '0' : '1');
divide_by_two(input, input_len);
}
free(input);
char* output = queue_get_arr(&queue);
printf("%s\n", output);
free(output);
free_char_queue(&queue);
}
}
This is not the fastest approach, but it is very simple. Also feel free to optimize it.
How do I convert a really long string (as decimal characters) to binary?
Let us look at printing this.
print2(s)
If the decimal string is at least "2",
__ Divide the decimal string by 2 and notice its remainder.
__ Recursively call print2(s)
__ Print the remainder.
Else print the string.
Example code:
#include <stdio.h>
unsigned decimal_string_divide(char *dividend, unsigned divisor) {
// Remove a potential leading '0'
if (*dividend == '0') {
memmove(dividend, dividend+1, strlen(dividend));
}
// "divide", like we learned in grade school.
unsigned remainder = 0;
while (*dividend) {
unsigned sum = remainder*10 + (*dividend - '0');
remainder = sum%divisor;
*dividend = sum/divisor + '0';
dividend++;
}
return remainder;
}
void decimal_string_print_binary(char *dividend) {
//printf("<%s>\n", dividend); fflush(stdout);
if (dividend[0]) {
// If at least 2 digits or at least "2"
if (dividend[1] || (dividend[0] >= '2')) {
unsigned bit = decimal_string_divide(dividend, 2);
decimal_string_print_binary(dividend);
printf("%c", bit + '0');
} else {
printf("%c", *dividend);
}
}
}
void decimal_string_print_2(const char *dividend) {
printf("%-25s", dividend);
size_t sz = strlen(dividend) + 1;
char buf[sz]; // Use a VLA or allocate memory
strcpy(buf, dividend);
decimal_string_print_binary(buf);
printf("\n");
}
Test
int main(void) {
decimal_string_print_2("0");
decimal_string_print_2("1");
decimal_string_print_2("42");
decimal_string_print_2("8675309");
decimal_string_print_2("18446744073709551615");
}
Output
0 0
1 1
42 101010
8675309 100001000101111111101101
18446744073709551615 1111111111111111111111111111111111111111111111111111111111111111
To instead convert the string from decimal form into a binary string, allocate sufficient buffer (about log10(2) times string length) and instead of printing above, save to the buffer. Left for OP to do.
I am suggesting a better approach. whereby any arguments passed to a function that is not intended to be mutated, be received as a "const", and a local pointer be used to access the data of this "const".
IE:
void to_binary(const char *str) {
char *ptr = str;
...
Then use ptr.
I know that in this case, my argument is purely trivial and academic, but it is a good practice to get used to and may save you many headaches in the future.
Also, when dealing with binary data, use "unsigned char", to ensure that no type conversions are used. You will need bit 7 if the data is not ASCII or alike.
I encountered a hard question I don't know the answer to: "Rearrange the digits from an integer in blocks of two with a recursive function" here's an example:
Input: 123456
unsigned long pairinvPrint(unsigned long number) {
printf("%d", number % 100);
if ((number / 100) <= 99) {
printf("%d", number / 100);
}
else {
pairinv(number / 100);
}
}
Output: 563412
More I/O Examples: 42 -> 42; 1234 -> 3412
However, the set circumstances to do this are hard (no loops, arrays, pointers, global- or static variables, no libraries) and it should not print the solution directly, rather return it upon a call like this:
printf("Rearrange int (%lu) = %lu", input, pairinvert(input));
Luckily there's one circumstance to make it easier, the number of the input digits is always even.
Now I experimented for a while, but cant come up with a working solution, except the invalid one using printf.
Does anyone have some inspiration for me or idea how to tackle this?
I'll bite :-)
unsigned long p(unsigned long p1, unsigned long p2) {
// no loops, no arrays, no pointers, no global, no static, no variables, no libraries
if (p1 < 100) return p2*100 + p1;
return p(p1/100, p2*100 + p1%100);
}
unsigned long pairinvert(unsigned long n) {
// no loops, no arrays, no pointers, no global, no static, no variables, no libraries
if (n < 100) return n;
return p(n/100, n%100);
}
// need <stdio.h> for printf()
#include <stdio.h>
int main(void) {
unsigned long input;
input = 123456;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
input = 42;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
input = 1234;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
}
Following program should work.
#include <stdio.h>
void rearrange(int n, int *output) {
int lsd = 0, slsd = 0;
if(n == 0)
return;
if(n > 0) {
lsd = n%10;
}
if (n > 9) {
slsd = (n%100)/10;
}
*output = 100*(*output) + 10*slsd + lsd;
n = n/100;
rearrange(n, output);
}
int main() {
int n;
int output = 0;
scanf("%d", &n);
rearrange(n, &output);
printf("%d\n", output);
return 0;
}
It is simple to understand, so I am not writing any comments.
Note that it is tail recursive so with O2 optimization it can recurse infinitely.
Try this :
unsigned long pairinv(unsigned long number, unsigned long result) {
unsigned long n = number % 100; // Gets the two digit number
if (n == 0) return result; // If it's zero returns the result
result = result * 100 + n; // Else multiplies the result by 100, adds n
return pairinv(number / 100, result); // and continues by recursion
}
int main() {
unsigned long r= 0;
printf("%lu\n", pairinv(123456, r)); //==> 563412
return 0;
}
A simple problem but I can't get documentation about this kind of format: I want to print a float in a Fortran scientific notation, with its integer part always being zero.
printf("%0.5E",data); // Gives 2.74600E+02
I want to print it like this:
.27460E+03
How can I get this result as clean as possible?
If you only care about the integer part being 0 and not really leaving out the 0, i.e. if you're fine with 0.27460E+03 instead of .27460E+03 you could do something similar to this:
#include <stdio.h>
#include <stdlib.h>
void fortran_printf();
int main(void)
{
double num = 274.600;
fortran_printf(num);
exit(EXIT_SUCCESS);
}
void fortran_printf(double num)
{
int num_e = 0;
while (num > 1.0) {
num /= 10;
num_e++;
}
printf("%.5fE+%02d", num, num_e);
}
Otherwise you have to take a detour over strings. Note that the code above is only meant to get you started. It certainly doesn't handle any involved cases.
I tried doing this with log10() and pow(), but ended up having problems with rounding errors. So as commented by #Karoly Horvath, string manipulation is probably the best approach.
#include <stdlib.h>
char *fortran_sprintf_double(double x, int ndigits) {
char format[30], *p;
static char output[30];
/* Create format string (constrain number of digits to range 1–15) */
if (ndigits > 15) ndigits = 15;
if (ndigits < 1) ndigits = 1;
sprintf(format, "%%#.%dE", ndigits-1);
/* Convert number to exponential format (multiply by 10) */
sprintf(output, format, x * 10.0);
/* Move the decimal point one place to the left (divide by 10) */
for (p=output+1; *p; p++) {
if (*p=='.') {
*p = p[-1];
p[-1] = '.';
break;
}
}
return output;
}
A string manipulation approach:
int printf_NoIntegerPart(double x, int prec) {
char buf[20 + prec];
sprintf(buf, "%+.*E", prec - 1, x * 10.0); // use + for consistent width output
if (buf[2] == '.') {
buf[2] = buf[1];
buf[1] = '.';
}
puts(buf);
}
int main(void) {
printf_NoIntegerPart(2.74600E+02, 5); // --> +.27460E+03
}
This will print "INF" for |x| > DBL_MAX/10
printf() will not meet OP’s goal in one step using some special format. Using sprintf() to form the initial textual result is a good first step, care must be exercised when trying to do “math” with string manipulation.
Akin to #user3121023 deleted answer.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
int printf_NoIntegerPart(double x, int prec) {
assert(prec >= 2 && prec <= 100);
char buffer[prec + 16]; // Form a large enough buffer.
sprintf(buffer, "%.*E", prec - 1, x);
int dp = '.'; // Could expand code here to get current local's decimal point.
char *dp_ptr = strchr(buffer, dp);
char *E_ptr = strchr(buffer, 'E');
// Insure we are not dealing with infinity, Nan, just the expected format.
if (dp_ptr && dp_ptr > buffer && E_ptr) {
// Swap dp and leading digit
dp_ptr[0] = dp_ptr[-1];
dp_ptr[-1] = dp;
// If x was not zero …
if (x != 0) {
int expo = atoi(&E_ptr[1]); // Could use `strtol()`
sprintf(&E_ptr[1], "%+.02d", expo + 1);
}
}
return puts(buffer);
}
int main(void) {
printf_NoIntegerPart(2.74600E+02, 5); // ".27460E+03"
return 0;
}
Faced same issue while fortran porting.
DId not found std C format :(
Implemented both approaches - with log10/pow and with string manipulation.
#include <ansi_c.h>
#define BUFFL 16
// using log10 , 3 digits after "."
char* fformat1(char* b, double a) {
int sign = 1;
double mant;
double order;
int ord_p1;
if (a<0) {
sign =-1;
a = -a;
}
order=log10 (a);
if (order >=0) ord_p1 = (int) order +1; // due sto property of int
else ord_p1 = (int) order;
mant=a/(pow(10,ord_p1));
sprintf(b,"%.3fE%+03d",mant,ord_p1);
if (sign==-1) b[0]='-';
return b;
}
// using string manipulation
char* fformat2(char* b, double a) {;
int sign = 1;
int i;
int N=3;
if (a<0) {
sign =-1;
a = -a;
}
sprintf(b,"%0.3E",a*10); // remember - we *10 to have right exponent
b[1]=b[0]; // 3.123 => .3123
b[0]='.';
for (i=N; i>=0; i--) // and shif all left
b[i+1]=b[i];
b[0]='0'; // pad with zero 0.312
if (sign==-1) b[0]='-'; // sign if needed
return b;
}
int main () {
char b1[BUFFL]; // allocate buffer outside.
char b2[BUFFL];
char b3[BUFFL];
char b4[BUFFL];
char b5[BUFFL];
printf("%s %s %s %s %s \n", fformat(b1,3.1), fformat(b2,-3.0), fformat(b3,3300.),
fformat(b4,0.03), fformat(b5,-0.000221));
printf("%s %s %s %s %s \n", fformat2(b1,3.1), fformat2(b2,-3.0), fformat2(b3,3300.),
fformat2(b4,0.03), fformat2(b5,-0.000221));
return 1;
}
I want to know if there is a function in C library that convert a decimal to binary number and save number by number in a position on an array.
For example: 2 -> 10 -> array [0] = 0 array[1] = 1.
Thanks.
here:
void dec2bin(int c)
{
int i = 0;
for(i = 31; i >= 0; i--){
if((c & (1 << i)) != 0){
printf("1");
}else{
printf("0");
}
}
}
But this only prints the value of an integer in binary format. All data is represented in binary format internally anyway.
You did not define what is a decimal number for you. I am guessing it is character representation (e.g. in ASCII) of that number.
Notice that numbers are just numbers. Binary or decimal numbers do not exist, but a given number may have a binary, and a decimal, representation. Numbers are not made of digits!
Then you probably want sscanf(3) or strtol(3) pr atoi to convert a string to an integer (e.g. an int or a long), and snprintf(3) to convert an integer to a string.
If you want to convert a number to a binary string (with only 0 or 1 char-s in it) you need to code that conversion by yourself. To convert a binary string to some long use strtol.
There is no such function in C standard library. Anyway, you can write your own:
void get_bin(int *dst, intmax_t x);
Where dst is the resulting array (with 1s and 0s), and x is the decimal number.
For example:
C89 version:
#include <limits.h>
void get_bin(int *dst, int x)
{
int i;
for (i = sizeof x * CHAR_BIT - 1; i >= 0; --i)
*dst++ = x >> i & 1;
}
C99 version:
/* C99 version */
#include <limits.h>
#include <stdint.h>
void get_bin(int *dst, intmax_t x)
{
for (intmax_t i = sizeof x * CHAR_BIT - 1; i >= 0; --i)
*dst++ = x >> i & 1;
}
It works as follow: we run through the binary representation of x, from left to right. The expression (sizeof x * CHAR_BIT - 1) give the number of bits of x - 1. Then, we get the value of each bit (*dst++ = x >> i & 1), and push it into the array.
Example of utilisation:
void get_bin(int *dst, int x)
{
int i;
for (i = sizeof x * CHAR_BIT - 1; i >= 0; --i)
*dst++ = x >> i & 1;
}
int main(void)
{
int buf[128]; /* binary number */
int n = 42; /* decimal number */
unsigned int i;
get_bin(buf, n);
for (i = 0; i < sizeof n * CHAR_BIT; ++i)
printf("%d", buf[i]);
return 0;
}
Here is a version that explicitly uses a string buffer:
#include <string.h>
const char *str2bin(int num, char buffer[], const int BUFLEN)
{
(void) memset(buffer, '\0', BUFLEN );
int i = BUFLEN - 1; /* Index into buffer, running backwards. */
int r = 0; /* Remainder. */
char *p = &buffer[i - 1]; /* buffer[i] holds string terminator '\0'. */
while (( i >= 0 ) && ( num > 0 )) {
r = num % 2;
num = num / 2;
*p = r + '0';
i--;
p--;
}
return (p+1);
}
Use char * itoa ( int value, char * str, int base );
Find more here ...
the function should go like this:
int dec2bin(int n){
static int bin,osn=1,c;
if(n==0) return 0;
else {
c=n%2;
bin += c*osn;
osn*=10;
dec2bin(n/2);
}
return bin;
}
As far as i know there is no such function in any C library. But here's a recursive function that returns a binary representation of a decimal number as int:
int dec2bin(int n)
{
if(n == 0) return 0;
return n % 2 + 10 * dec2bin(n / 2);
}
The max number that it can represent is 1023 (1111111111 in binary) because of int data type limit, but you can substitute int for long long data type to increase the range. Then, you can store the return value to array like this:
int array[100], i = 0;
int n = dec2bin(some_number);
do{
array[i] = n % 10;
n /= 10;
i++;
}while(n > 10)
I know this is an old post, but i hope this will still help somebody!
If it helps you can convert any decimal to binary using bitset library, for example:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main(){
int decimal = 20;
bitset<5> binary20(decimal);
cout << binary20 << endl;
return 0;
}
So, you have an output like 10100. Bitsets also have a "toString()" method for any purpose.
I need to write a C program that will compare the number of digits before decimal point and after the decimal point and make sure they are equal.
How can I count how many powers of ten we have before and after the decimal point?
Here is what I have so far:
void main()
{
is_equal(6757.658);
}
INT is_equal(double x)
{
int digits = 0;
while (x) {
x /= 10;
digits++;
}
printf("%d ",digits);
}
Is there a better way to do this?
You do not seem to know binary representation of double/float variables as #AProgrammer suggests.
Your job is impossible if you use float/double. You may use string for the job.
something like below.NOTE: it's just a hint and not a good style.
EDIT: disable cout since this is C
bool checkFloat(string); //the function checks whether the string have a float number format
void twoPart(string num)
{
if (!checkFloat(num))
return;
int i = 0;
int a = 0;//integer part
int b = 0;//fractional part
for(;i<num.length() && num[i]!='.'; i ++);
a = i;
b = num.length() - a - 1;
if(i == num.length())
b = 0;
// print the result here
//cout << a << " " << b << endl;
}
The above piece of code accepts number like 123, 123.456, .123
That's a bit tricky. IEEE floats can't represent most decimal fractions exactly. The number 6757.658 is represented as a binary decimal: 0x1a65a872b020c5×2-40, which is exactly 6757.6580000000003565219230949878692626953125 (I think). I.e., your number actually has 40 decimal places.
This simplest work-around is to format it using something like sprintf(buf, "%.10g", x);, then read the parts back using int a, b; sscanf(buf, "%d.%d", &a, &b);. Alternatively, you could start with int b = 1e10*(x - floor(x)) and keep dividing b by 10 until it isn't a multiple of 10 (while (b%10 == 0) b /= 10;).
3rd try:
Count the number of "digits" before and after a "."
Null is considered not equal to anything
I did not test this code it might contain typos.
int is_equal(char *buffer)
{
char *temp;
int leftLen,rightLen;
temp = strtok(buffer,".");
if (temp == null) return false;
leftLen = strlen(temp);
temp = strtok(buffer,".");
if (temp == null) return false;
rightLen = strlen(temp);
return (leftLen == rightLen);
}
Old stuff...
There are going to be lots of problems here, a floating point (double) in C is not always accurate to 100%; If you perform multiplication or division. If you multiply the digits will change.
The best way to solve this problem is to render the double to a string and then parse that string.
You can use sprintf to write the formatted double to a buffer.
OR
You can skip using a double all together and use a string to start with.
Thus building on Marcelo's answer:
Read the string from the user into a buffer called buff
Then parse it with a statement like sscanf(buf, "%d.%d", &a, &b);
buff is a char * or a char [], a and b are int. You test by saying a == b
void main()
{
is_equal("6757.658");
}
int is_equal(char *x)
{
int left,right;
sscanf(x, "%d.%d", &left, &right);
printf("Left digits: %d\n\r",left);
printf("Right digits: %d\n\r",right);
return (left == right);
}
#include <stdio.h>
#include <assert.h>
float main(void)
{
int siz;
assert (sizeof siz == sizeof (float));
siz = is_equal(6757.658);
printf( "Size=%d\n", siz);
return 0.0;
}
int is_equal(double x)
{
int digits;
for (digits=0; x >= 1.0; digits++) {
x /= 10;
}
return digits;
}