This may be a silly question, but... I tried to implement printf, but for some reason the output I get is not exactly what I expected. any idea what it could be? I would appreciate some help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
static int print(const char *restrict fmt, ...);
static int getfloat(float *);
static char *itoa(int, char *, int);
static void _strrev(char *);
int
main(void)
{
float i1 = 0.0, i2 = 0.0, noi1 = 0.0, noi2 = 0.0, res = 0.0;
print("weight - item 1: ");
getfloat(&i1);
print("no. of item 1: ");
getfloat(&noi1);
print("weight - item 2: ");
getfloat(&i2);
print("no. of item 2: ");
getfloat(&noi2);
res = ((i1 * noi1) + (i2 * noi2)) / (noi1 + noi2);
print("%f\n", res);
exit(EXIT_SUCCESS);
}
static int
print(const char *restrict fmt, ...)
{
va_list ap;
char buf[BUFSIZ] = {0}, tmp[20] = {0};
char *str_arg;
int i = 0, j = 0;
va_start(ap, fmt);
while (fmt[i] != '\0') {
if (fmt[i] == '%') {
i++;
switch (fmt[i]) {
case 'c':
buf[j] = (char)va_arg(ap, int);
j++;
break;
case 'd':
itoa(va_arg(ap, int), tmp, 10);
strcpy(&buf[j], tmp);
j += strlen(tmp);
break;
case 'f':
gcvt(va_arg(ap, double), 10, tmp);
strcpy(&buf[j], tmp);
j += strlen(tmp);
break;
case 's':
str_arg = va_arg(ap, char *);
strcpy(&buf[j], str_arg);
j += strlen(str_arg);
break;
default:
break;
}
} else { buf[j++ ] = fmt[i]; }
++i;
}
fwrite(buf, j, 1, stdout);
va_end(ap);
return (j);
}
static int
getfloat(float *p)
{
int c, sign = 0;
float pwr = 0.0;
while (c = getc(stdin), c == ' ' || c == '\t' || c == '\n')
; /* ignore white spaces */
sign = 1; /* record sign */
if (c == '+' || c == '-') {
sign = (c == '+') ? 1 : -1;
c = getc(stdin);
}
for (*p = 0.0; isdigit(c); c = getc(stdin))
*p = 10.0 * *p + c - '0';
if (c == '.') { c = getc(stdin); }
for (pwr = 1.0; isdigit(c); c = getc(stdin)) {
*p = 10.0 * *p + c - '0';
pwr *= 10.0;
}
*p *= sign / pwr;
if (c != EOF)
ungetc(c, stdout);
return (float)c;
}
static char *
itoa(int n, char *strout, int base)
{
int i, sign;
if ((sign = n) < 0)
n -= n;
i = 0;
do {
strout[i++] = n % base + '0';
} while ((n /= base) != 0);
if (sign < 0) { strout[i++] = '-'; }
strout[i] = '\0';
_strrev(strout);
return (strout);
}
static void
_strrev(char *str)
{
int i = 0, j = strlen(str) - 1;
for ( ; i < j; ++i, --j) {
int tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
here is the output I get:
19.44444466
and this is the output that I expect: (or the one that I would at least like to receive, which is the one in itself that I get when I use printf)
19.444445
f, F The double argument is rounded and converted to decimal
notation in the style [-]ddd.ddd, where the number of
digits after the decimal-point character is equal to the
precision specification. If the precision is missing, it
is taken as 6;
https://man7.org/linux/man-pages/man3/printf.3.html
The default precision for %f is six so printf() is rounding the result to six decimal places.
You'd need to play with the ndigit argument to gcvt() which is the total number of significant digits (both before and after the decimal point). You are passing in 10 so your answer has two digits before the decimal and eight after for this particular number.
Seems that gcvt() don't do exactly what printf() do, at least with your compiler. Check it with a "real" printf with the same value.
Since you didn't gave the numbers you used for the test (avoid getfloat() and initialize directly i1, i2, noi1 and noi2 with required constants in your question), I can't run it and tell you why exactly - or if it even happens with my own compiler.
Usually, the source code for printf is at least two times bigger than yours, so you may have missed some vicious subcases. If I remember well, printf has code to decode an IEEE-754 directly and don't rely on gcvt.
Related
I'm trying to figure what is wrong with my code as it always skips only to the printf("not an octal number part"); and only outputs that although has many of the other computations before it, i'm trying to debug it but can't seem to find the error. this is the summer of the problem below, also we are not allowed to use pointers yet.
A C program to input an octal number in the form of a line of characters and store the input characters in an array. Convert the octal number to a decimal integer and display the decimal integer on the standard output using printf.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
int main() {
char my_strg[MAX_SIZE];
int c;
int res = 0;
int i = 0;
while ( (c = getchar()) != '\n') {
my_strg[i] = c;
i++;
}
int k = 0;
for(k = strlen(my_strg)-1; k >= 0; k--) {
if((my_strg[k] >= '0') && (my_strg[k] <= '7')) {
res += (pow(8, k) * (my_strg[k]-'0'));
} else if(my_strg[k] == '-') {
res *= -1;
} else {
printf("not an octal number");
break;
}
k++;
}
printf("%d\n", res);
}
You haven't null-terminated my_strg. This means that the beginning of the array contains the input, but the rest of it contains gibberish. It may also be a good idea to do bounds checking so that you don't get a buffer overflow.
while (((c = getchar()) != '\n') && (i < MAX_SIZE-1)) {
my_strg[i] = c;
my_strg[i+1] = '\0';
i++;
}
very simple function. Needs more error checking.
Note 'a' != 'A'. The base can be as big as number of chars in the digits table
static const char digits[] = "0123456789abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRTSTUWXYZ";
long long ALMOST_anybase(const char *str, int base, int *errCode)
{
long long result = 0;
int sign = 1;
if(errCode) *errCode = 0;
if(str)
{
if(*str == '-') {sign = -1; str++;}
while(*str)
{
if(*str == '-')
{
if(errCode) *errCode = 3;
break;
}
else
{
char *ch;
if((ch = strchr(digits, *str)))
{
if(ch - digits >= base)
{
if(errCode) *errCode = 2;
break;
}
result *= base;
result += (ch - digits);
}
else
{
if(errCode) *errCode = 1;
break;
}
}
str++;
}
}
return result * sign;
}
int main(void)
{
int errCode;
long long result;
result = ALMOST_anybase("-4-4", 10, &errCode);
if(errCode)
{
printf("Wrong input string ErrCode = %d\n", errCode);
}
else
{
printf("result = %lld\n", result);
}
}
strtol converts the inputed string str to a long value of any specified base of 2 to 36. strtof() offers a similar functionality but without allowing your to specify base. Is there another function that does the same as strtof but allows you to select base?
e.g Lets say 101.101 is inputted as a string. I want to be able to do
strtof("101.101", null, 2);
and get an output of 5.625.
You can parse the string to split it in the . and convert the part before and the part after to decimal. Afterwards, you can create a float out of that string. Here is a simple function that accomplishes that.
float new_strtof(char* const ostr, char** endptr, unsigned char base)
{
char* str = (char*)malloc(strlen(ostr) + 1);
strcpy(str, ostr);
const char* dot = ".";
/* I do not validate any input here, nor do I do anything with endptr */ //Let's assume input of 101.1101, null, 2 (binary)
char *cbefore_the_dot = strtok(str, dot); //Will be 101
char *cafter_the_dot = strtok(NULL, dot); //Will be 0101
float f = (float)strtol (cbefore_the_dot, 0, base); //Base would be 2 = binary. This would be 101 in decimal which is 5
int i, sign = (str[0] == '-'? -1 : 1);
char n[2] = { 0 }; //will be just for a digit at a time
for(i = 0 ; cafter_the_dot[i] ; i++) //iterating the fraction string
{
n[0] = cafter_the_dot[i];
f += strtol(n, 0, base) * pow(base, -(i + 1)) * sign; //converting the fraction part
}
free(str);
return f;
}
One could manage this in a more efficient and less dirty way but this is just an example to show you the idea behind this. The above works well for me.
Don't forget to #include <math.h> and compile with -lm flag. An example would be gcc file.c -o file -lm.
Calculations with FP can incur accumulated round off errors and other subtleties. The below simply calculates the whole number part and the fractional part as 2 base-n integers and then, with minimally FP calculation, derives the answer.
Code also needs to cope with a negative whole number part and insure the fractional part is treated with the same sign.
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
double CC_strtod(const char *s, char **endptr, int base) {
char *end;
if (endptr == NULL) endptr = &end;
long ipart = strtol(s, endptr, base);
if ((*endptr)[0] == '.') {
(*endptr)++;
char *fpart_start = *endptr;
// Insure `strtol()` is not fooled by a space, + or -
if (!isspace((unsigned char) *fpart_start) &&
*fpart_start != '-' && *fpart_start != '+') {
long fpart = strtol(fpart_start, endptr, base);
if (ipart < 0) fpart = -fpart;
return fma(fpart, pow(base, fpart_start - *endptr), ipart);
}
}
return ipart;
}
int main() {
printf("%e\n", CC_strtod("101.101", NULL, 2));
}
Output
5.625000e+00
The above is limited in that the two parts should not exceed the range of long. Code could use wider types like intmax_t for a less restrictive function.
For comparison, here's a simple, straightforward version of atoi(), that accepts an arbitrary base to use (i.e. not necessarily 10):
#include <ctype.h>
int myatoi(const char *str, int b)
{
const char *p;
int ret = 0;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
ret = b * ret + (*p - '0');
return ret;
}
(Note that I have left out negative number handling.)
Once you've got that, it's straightforward to detect a decimal point and handle digits to the right of it as well:
double myatof(const char *str, int b)
{
const char *p;
double ret = 0;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
ret = b * ret + (*p - '0');
if(*p == '.')
{
double fac = b;
for(p++; *p != '\0' && isdigit(*p); p++)
{
ret += (*p - '0') / fac;
fac *= b;
}
}
return ret;
}
A slightly less obvious approach, which might be numerically better behaved, is:
double myatof2(const char *str, int b)
{
const char *p;
long int n = 0;
double denom = 1;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
n = b * n + (*p - '0');
if(*p == '.')
{
for(p++; *p != '\0' && isdigit(*p); p++)
{
n = b * n + (*p - '0');
denom *= b;
}
}
return n / denom;
}
I tested these with
#include <stdio.h>
int main()
{
printf("%d\n", myatoi("123", 10));
printf("%d\n", myatoi("10101", 2));
printf("%f\n", myatof("123.123", 10));
printf("%f\n", myatof("101.101", 2));
printf("%f\n", myatof2("123.123", 10));
printf("%f\n", myatof2("101.101", 2));
return 0;
}
which prints
123
21
123.123000
5.625000
123.123000
5.625000
as expected.
One more note: these functions don't handle bases greater than 10.
I'm extremely lost and confused.
I have to read in a float integer like 3.432 using getchar. Then, I have to print it out again as a float with a precision of 4 decimal places using printf. So 3.432 --> 3.4320 and .450 --> .4500, and 453 --> 453.0000.
I've been using getchar() and I understand that, but trying to reconvert the value as a float is where I'm just extremely lost.
float num = 0.0;
char ch;
while((ch = getchar()) != '\n'){
num = ch - '0';
printf("%.4f", num);
}
I know why that is wrong and what it outputs but that's what I have so far
EDIT: I can only use getchar to read the float values
Not tested (no time). Hope it helps.
#include <stdio.h>
int main(void)
{
float num = 0.0;
float i = 1.0;
char ch;
printf("Enter a float number: ");
while((ch = getchar()) != '\n')
{
if (ch == '.')
{
i = 0.1;
}
else if ((ch>= '0') && (ch <='9'))
{
if (i==1)
{
num *= 10;
num += ch - '0';
}
else
{
num += (ch - '0') * i;
i /= 10;
}
}
}
printf("%.4f\n", num);
return 0;
}
Ok, so you should first specify what you want - as usual keep away from the keybord until you exactly know what you want to build:
read until end of file or first new line
skip initial blank characters (optional but not expensive)
ignore trailing blank character (optional but not expensive)
reject any non blank after first trailing blank
reject any character other than blanks, digits and dot
process the integer part (until first dot) but multiplying current value by 10 and adding character code minus char '0'
ensure at most one dot
process the decimal part by adding char - '0' multiplied by 0.1 power decimal position
Once that has been stated coding is simple and could be:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void error(int pos, char c) {
fprintf(stderr, "Unwanted character %c at %d\n", c, pos);
exit(1);
}
int main() {
double f = 0.;
int c;
bool initial = 1, final=0;
int pos = 0;
double decimal = 0;
while (((c = getchar()) != EOF) && (c != '\n')) {
pos += 1;
if (isspace(c)) { // accept spaces before and after the number
if (initial || final) continue;
else {
final = 1;
continue;
}
}
else if (final) { // do not accept anything after a space after the number
error(pos, c);
}
initial = 0; // at least one non blank char
if (c == '.') {
if (decimal) { // accept only one decimal dot
error(pos, c);
}
else decimal = 1;
}
else if (! isdigit(c)) { // only digits
error(pos, c);
}
else if (decimal == 0) {
f = f * 10 + c - '0'; // integer part
}
else {
decimal *= .1; // fractional part
f += (c - '0') * decimal;
}
}
printf("%.4f\n", f);
return 0;
}
As a bonus I showed you how to process error conditions
It would be simpler if you first write a function reading integer.
Then you can think about writing a function reading the decimal part and combine the result.
Also, you need to accumulate the read information. At the moment you are overwriting previously read digit with a new one.
Another possibility using only stdio in solving the task could be a simple two-step process:
declaring and reading the input into a character array, using some more or less sophisticated fool-proofing
"parsing" the array members on the left and right hand side of the decimal point and multiplying the ('0' offset subtracted value) by the corresponding power of 10.
_
#include <stdio.h>
int main(void)
{
float power_of_ten, num = 0.;
char c, ch[32];
int j, i = 0;
int point_pos = -1; //initialize decimal point position 'offscale'
while(((c = getchar()) != EOF) && (c != '\n')) //simple fool-proof check
if(((c >= '0')&&(c <= '9')) || (( c == '.')&&(point_pos == -1))){
ch[i] = c;
if(ch[i] == '.')
point_pos = i;
i++;
}
ch[++i] = '\0'; //length of the array
//parsing the array
if(point_pos >= 0){ //to the right of decimal point
power_of_ten = .1;
for(j = point_pos + 1; j < i-1; j++){
num += (float)(ch[j] - '0')*power_of_ten;
power_of_ten *= .1;
}
}
power_of_ten = 1.; //to the left of decimal point
if(point_pos == -1)point_pos = i-1;
for(j = point_pos - 1; j >= 0 ; j --){
num += (float)(ch[j] - '0')*power_of_ten;
power_of_ten *= 10;
}
printf("%.4f\n", num);
return 0;
}
Hope this helps!!
#include<stdio.h>
#include<string.h>
#include<math.h>
int findNumOfDigits(int num);
int main(void)
{
char c;
float f, mod, fractional;
char *buff = malloc(10), *fptr;
char *str = buff;
int digits;
printf("Enter any number\n");
c = getchar();
while(c!='\n')
{
*buff = c;
buff = buff+1;
c = getchar();
}
*buff = '\0';
mod = atoi(str);
fptr = strstr(str, ".");
if(fptr!=NULL)
fptr++;
fractional = atoi(fptr);
digits = findNumOfDigits(fractional);
f = (mod + (fractional/pow(10,digits)));
printf("Number converted to float = %f", f);
return 0;
}
int findNumOfDigits(int num)
{
int i;
for(i = 1; num >= 10; i++)
{
num = num/10;
}
return i;
}
I'm working on an embedded DSP where speed is crucial, and memory is very short.
At the moment, sprintf uses the most resources of any function in my code. I only use it to format some simple text: %d, %e, %f, %s, nothing with precision or exotic manipulations.
How can I implement a basic sprintf or printf function that would be more suitable for my usage?
This one assumes the existence of an itoa to convert an int to character representation, and an fputs to write out a string to wherever you want it to go.
The floating point output is non-conforming in at least one respect: it makes no attempt at rounding correctly, as the standard requires, so if you have have (for example) a value of 1.234 that is internally stored as 1.2399999774, it'll be printed out as 1.2399 instead of 1.2340. This saves quite a bit of work, and remains sufficient for most typical purposes.
This also supports %c and %x in addition to the conversions you asked about, but they're pretty trivial to remove if you want to get rid of them (and doing so will obviously save a little memory).
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
static void ftoa_fixed(char *buffer, double value);
static void ftoa_sci(char *buffer, double value);
int my_vfprintf(FILE *file, char const *fmt, va_list arg) {
int int_temp;
char char_temp;
char *string_temp;
double double_temp;
char ch;
int length = 0;
char buffer[512];
while ( ch = *fmt++) {
if ( '%' == ch ) {
switch (ch = *fmt++) {
/* %% - print out a single % */
case '%':
fputc('%', file);
length++;
break;
/* %c: print out a character */
case 'c':
char_temp = va_arg(arg, int);
fputc(char_temp, file);
length++;
break;
/* %s: print out a string */
case 's':
string_temp = va_arg(arg, char *);
fputs(string_temp, file);
length += strlen(string_temp);
break;
/* %d: print out an int */
case 'd':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 10);
fputs(buffer, file);
length += strlen(buffer);
break;
/* %x: print out an int in hex */
case 'x':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 16);
fputs(buffer, file);
length += strlen(buffer);
break;
case 'f':
double_temp = va_arg(arg, double);
ftoa_fixed(buffer, double_temp);
fputs(buffer, file);
length += strlen(buffer);
break;
case 'e':
double_temp = va_arg(arg, double);
ftoa_sci(buffer, double_temp);
fputs(buffer, file);
length += strlen(buffer);
break;
}
}
else {
putc(ch, file);
length++;
}
}
return length;
}
int normalize(double *val) {
int exponent = 0;
double value = *val;
while (value >= 1.0) {
value /= 10.0;
++exponent;
}
while (value < 0.1) {
value *= 10.0;
--exponent;
}
*val = value;
return exponent;
}
static void ftoa_fixed(char *buffer, double value) {
/* carry out a fixed conversion of a double value to a string, with a precision of 5 decimal digits.
* Values with absolute values less than 0.000001 are rounded to 0.0
* Note: this blindly assumes that the buffer will be large enough to hold the largest possible result.
* The largest value we expect is an IEEE 754 double precision real, with maximum magnitude of approximately
* e+308. The C standard requires an implementation to allow a single conversion to produce up to 512
* characters, so that's what we really expect as the buffer size.
*/
int exponent = 0;
int places = 0;
static const int width = 4;
if (value == 0.0) {
buffer[0] = '0';
buffer[1] = '\0';
return;
}
if (value < 0.0) {
*buffer++ = '-';
value = -value;
}
exponent = normalize(&value);
while (exponent > 0) {
int digit = value * 10;
*buffer++ = digit + '0';
value = value * 10 - digit;
++places;
--exponent;
}
if (places == 0)
*buffer++ = '0';
*buffer++ = '.';
while (exponent < 0 && places < width) {
*buffer++ = '0';
--exponent;
++places;
}
while (places < width) {
int digit = value * 10.0;
*buffer++ = digit + '0';
value = value * 10.0 - digit;
++places;
}
*buffer = '\0';
}
void ftoa_sci(char *buffer, double value) {
int exponent = 0;
int places = 0;
static const int width = 4;
if (value == 0.0) {
buffer[0] = '0';
buffer[1] = '\0';
return;
}
if (value < 0.0) {
*buffer++ = '-';
value = -value;
}
exponent = normalize(&value);
int digit = value * 10.0;
*buffer++ = digit + '0';
value = value * 10.0 - digit;
--exponent;
*buffer++ = '.';
for (int i = 0; i < width; i++) {
int digit = value * 10.0;
*buffer++ = digit + '0';
value = value * 10.0 - digit;
}
*buffer++ = 'e';
itoa(exponent, buffer, 10);
}
int my_printf(char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(stdout, fmt, arg);
va_end(arg);
return length;
}
int my_fprintf(FILE *file, char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(file, fmt, arg);
va_end(arg);
return length;
}
#ifdef TEST
int main() {
float floats[] = { 0.0, 1.234e-10, 1.234e+10, -1.234e-10, -1.234e-10 };
my_printf("%s, %d, %x\n", "Some string", 1, 0x1234);
for (int i = 0; i < sizeof(floats) / sizeof(floats[0]); i++)
my_printf("%f, %e\n", floats[i], floats[i]);
return 0;
}
#endif
I wrote nanoprintf in an attempt to find a balance between tiny binary size and having good feature coverage. As of today the "bare-bones" configuration is < 800 bytes of binary code, and the "maximal" configuration including float parsing is < 2500 bytes. 100% C99 code, no external dependencies, one header file.
https://github.com/charlesnicholson/nanoprintf
I haven't seen a smaller vsnprintf implementation than this that has a comparable feature set. I also released the software in the public domain and with the Zero-clause BSD license so it's fully unencumbered.
Here's an example that uses the vsnprintf functionality:
your_project_nanoprintf.c
#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0
// Compile nanoprintf in this translation unit.
#define NANOPRINTF_IMPLEMENTATION
#include "nanoprintf.h"
your_log.h
void your_log(char const *s);
void your_log_v(char const *fmt, ...);
your_log.c
#include "your_log.h"
#include "nanoprintf.h"
#include <stdarg.h>
void your_log_v(char const *s) {
// Do whatever you want with the fully formatted string s.
}
void your_log(char const *fmt, ...) {
char buf[128];
va_arg args;
va_start(args, fmt);
npf_vsnprintf(buf, sizeof(buf), fmt, args); // Use nanoprintf for formatting.
va_end(args);
your_log_write(buf);
}
Nanoprintf also provides an snprintf-alike and a custom version that takes a user-provided putc callback for things like UART writes.
I add here my own implementation of (v)sprintf, but it does not provide float support (it is why I am here...).
However, it implements the specifiers c, s, d, u, x and the non standard ones b and m (binary and memory hexdump); and also the flags 0, 1-9, *, +.
#include <stdarg.h>
#include <stdint.h>
#define min(a,b) __extension__\
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
enum flag_itoa {
FILL_ZERO = 1,
PUT_PLUS = 2,
PUT_MINUS = 4,
BASE_2 = 8,
BASE_10 = 16,
};
static char * sitoa(char * buf, unsigned int num, int width, enum flag_itoa flags)
{
unsigned int base;
if (flags & BASE_2)
base = 2;
else if (flags & BASE_10)
base = 10;
else
base = 16;
char tmp[32];
char *p = tmp;
do {
int rem = num % base;
*p++ = (rem <= 9) ? (rem + '0') : (rem + 'a' - 0xA);
} while ((num /= base));
width -= p - tmp;
char fill = (flags & FILL_ZERO)? '0' : ' ';
while (0 <= --width) {
*(buf++) = fill;
}
if (flags & PUT_MINUS)
*(buf++) = '-';
else if (flags & PUT_PLUS)
*(buf++) = '+';
do
*(buf++) = *(--p);
while (tmp < p);
return buf;
}
int my_vsprintf(char * buf, const char * fmt, va_list va)
{
char c;
const char *save = buf;
while ((c = *fmt++)) {
int width = 0;
enum flag_itoa flags = 0;
if (c != '%') {
*(buf++) = c;
continue;
}
redo_spec:
c = *fmt++;
switch (c) {
case '%':
*(buf++) = c;
break;
case 'c':;
*(buf++) = va_arg(va, int);
break;
case 'd':;
int num = va_arg(va, int);
if (num < 0) {
num = -num;
flags |= PUT_MINUS;
}
buf = sitoa(buf, num, width, flags | BASE_10);
break;
case 'u':
buf = sitoa(buf, va_arg(va, unsigned int), width, flags | BASE_10);
break;
case 'x':
buf = sitoa(buf, va_arg(va, unsigned int), width, flags);
break;
case 'b':
buf = sitoa(buf, va_arg(va, unsigned int), width, flags | BASE_2);
break;
case 's':;
const char *p = va_arg(va, const char *);
if (p) {
while (*p)
*(buf++) = *(p++);
}
break;
case 'm':;
const uint8_t *m = va_arg(va, const uint8_t *);
width = min(width, 64); // buffer limited to 256!
if (m)
for (;;) {
buf = sitoa(buf, *(m++), 2, FILL_ZERO);
if (--width <= 0)
break;
*(buf++) = ':';
}
break;
case '0':
if (!width)
flags |= FILL_ZERO;
// fall through
case '1'...'9':
width = width * 10 + c - '0';
goto redo_spec;
case '*':
width = va_arg(va, unsigned int);
goto redo_spec;
case '+':
flags |= PUT_PLUS;
goto redo_spec;
case '\0':
default:
*(buf++) = '?';
}
width = 0;
}
*buf = '\0';
return buf - save;
}
int my_sprintf(char * buf, const char * fmt, ...)
{
va_list va;
va_start(va,fmt);
int ret = my_vsprintf(buf, fmt, va);
va_end(va);
return ret;
}
#if TEST
int main(int argc, char *argv[])
{
char b[256], *p = b;
my_sprintf(b, "%x %d %b\n", 123, 123, 123);
while (*p)
putchar(*p++);
}
#endif
tl;dr : Considering a smaller, but more complete, sprintf() implementation
https://github.com/eyalroz/printf
The standard library's sprintf() implementation you may be using is probably quite resource-taxing. But it's possible that you could avail yourself of a stand-alone sprintf() implementation, you would get more complete functionality without paying with so much memory use.
Now, why would you choose that if you've told us you only need some basic functionality? Because the nature of (s)printf() use is that we tend to use more aspects of it as we go along. You notice you want to print larger numbers, or differences in far decimal digits; you want to print a bunch of values and then decide you want them aligned. Or somebody else wants to use the printing capability you added to print something you haven't thought of. So, instead of having to switch implementations, you use an implementation where compile-time options configure which features get compiled and which get left out.
A friend of mine sent me this question. I haven't really been able to come up with any kind of algorithm to solve this problem.
You are provided with a no. say 123456789 and two operators * and +. Now without changing the sequence of the provided no. and using these operators as many times as you wish, evaluate the given value:
eg: given value 2097
Solution: 1+2+345*6+7+8+9
Any ideas on how to approach problems like these?
One of the easiest ways to do it is using shell expansion in BASH:
#!/bin/sh
for i in 1{,+,*}2{,+,*}3{,+,*}4{,+,*}5{,+,*}6{,+,*}7{,+,*}8{,+,*}9; do
if [ $(( $i )) == 2097 ]; then
echo $i = 2097
fi
done
which gives:
$ sh -c '. ./testequation.sh'
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097
There are not that many solutions - this python program takes under a second to bruteforce them all
from itertools import product
for q in product(("","+","*"), repeat=8):
e = ''.join(i+j for i,j in zip('12345678',q))+'9'
print e,'=',eval(e)
Here is a sample run through grep
$ python sums.py | grep 2097
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097
General solution is a simple modification
from itertools import product
def f(seq):
for q in product(("","+","*"), repeat=len(seq)-1):
e = ''.join(i+j for i,j in zip(seq[:-1],q))+seq[-1]
print e,'=',eval(e)
This isn't the easiest way, but I tried to write "optimized" code : genereting all the 3^(n-1) strings is expensive, and you've to evaluate a lot of them; I still used bruteforce, but cutting unproductive "subtrees" ( and the source is C, as requested in the title)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#define B 10
void rec_solve(char *, char *, int, char, int, char, int, char *);
int main(int argc, char** argv) {
char *n, *si = malloc(0);
if (argc < 2) {
printf("Use : %s num sum", argv[0]);
} else {
n = calloc(strlen(argv[1]), sizeof (char));
strncpy(n, argv[1], strlen(argv[1]));
rec_solve(n, si, 0, '+', 0, '+', atoi(argv[2]), n);
}
return 0;
}
void rec_solve(char *str, char *sig, int p, char ps, int l, char ls, int max, char *or) {
int i, len = strlen(str), t = 0, siglen = strlen(sig), j, k;
char *mul;
char *add;
char *sub;
if (p + l <= max) {
if (len == 0) {
k = (ls == '+') ? p + l : p*l;
if ((k == max) && (sig[strlen(sig) - 1] == '+')) {
for (i = 0; i < strlen(or) - 1; i++) {
printf("%c", or[i]);
if (sig[i] && (sig[i] != ' '))
printf("%c", sig[i]);
}
printf("%c\n", or[i]);
}
} else {
for (i = 0; i < len; i++) {
t = B * t + (str[i] - '0');
if (t > max)
break;
sub = calloc(len - i - 1, sizeof (char));
strncpy(sub, str + i + 1, len - i - 1);
mul = calloc(siglen + i + 1, sizeof (char));
strncpy(mul, sig, siglen);
add = calloc(strlen(sig) + i + 1, sizeof (char));
strncpy(add, sig, siglen);
for (j = 0; j < i; j++) {
add[siglen + j] = ' ';
mul[siglen + j] = ' ';
}
add[siglen + i] = '+';
mul[siglen + i] = '*';
switch (ps) {
case '*':
switch (ls) {
case '*':
rec_solve(sub, add, p*l, '*', t, '+',max, or);
rec_solve(sub, mul, p*l, '*', t, '*',max, or);
break;
case '+':
rec_solve(sub, add, p*l, '+', t, '+',max, or);
rec_solve(sub, mul, p*l, '+', t, '*',max, or);
break;
}
case '+':
switch (ls) {
case '*':
rec_solve(sub,add,p, '+',l*t,'+',max, or);
rec_solve(sub,mul,p, '+',l*t,'*',max, or);
break;
case '+':
rec_solve(sub,add,p + l,'+',t,'+',max, or);
rec_solve(sub,mul,p + l,'+',t,'*',max, or);
break;
}
break;
}
}
}
}
}
Here's an implementation of a non-recursive C bruteforce version that will work for any set of digits (with reasonable values in the 32-bit range and not just for the example above). Now complete. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple integer pow() function */
int pow(int base, int pow)
{
int i, res = 1;
for (i = 0; i < pow; i++)
res *= base;
return res;
}
/* prints a value in base3 zeropadded */
void zeropad_base3(int value, char *buf, int width)
{
int length, dif;
_itoa(value, buf, 3);
length = strlen(buf);
dif = width - length;
/* zeropad the rest */
memmove(buf + dif, buf, length+1);
if (dif)
memset(buf, '0', dif);
}
int parse_factors(char **expr)
{
int num = strtol(*expr, expr, 10);
for ( ; ; )
{
if (**expr != '*')
return num;
(*expr)++;
num *= strtol(*expr, expr, 10);
}
}
/* evaluating using recursive descent parser */
int evaluate_expr(char* expr)
{
int num = parse_factors(&expr);
for ( ; ; )
{
if (*expr != '+')
return num;
expr++;
num += parse_factors(&expr);
}
}
void do_puzzle(const char *digitsString, int target)
{
int i, iteration, result;
int n = strlen(digitsString);
int iterCount = pow(3, n-1);
char *exprBuf = (char *)malloc(2*n*sizeof(char));
char *opBuf = (char *)malloc(n*sizeof(char));
/* try all combinations of possible expressions */
for (iteration = 0; iteration < iterCount; iteration++)
{
char *write = exprBuf;
/* generate the operation "opcodes" */
zeropad_base3(iteration, opBuf, n-1);
/* generate the expression */
*write++ = digitsString[0];
for (i = 1; i < n; i++)
{
switch(opBuf[i-1])
{
/* case '0' no op */
case '1': *write++ = '+'; break;
case '2': *write++ = '*'; break;
}
*write++ = digitsString[i];
}
*write = '\0';
result = evaluate_expr(exprBuf);
if (result == target)
printf("%s = %d\n", exprBuf, result);
}
free(opBuf);
free(exprBuf);
}
int main(void)
{
const char *digits = "123456789";
int target = 2097;
do_puzzle(digits, target);
return 0;
}
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097
You could work backwards and try to test for all possibilities that could give solution;
e.g:
1 (something) 9 = 10
1*9=10 - false
1/9=10 - false
1-9=10 - false
1+9=10 - True
So, basically brute force - but it is re-usable code given that the input could be different.