comp.lang.c++
http://groups.google.com/group/comp.lang.c++?hl=en
comp.lang.c++@googlegroups.com
Today's topics:
* Overloaded template resolution - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/16d19f355b1d27b4?hl=en
* C++ standards committee looking at adding Cairo to the C++ standard - 10
messages, 6 authors
http://groups.google.com/group/comp.lang.c++/t/0b3c6e40a26c7051?hl=en
* Decoding GIF file in C? [Source code here] - 4 messages, 4 authors
http://groups.google.com/group/comp.lang.c++/t/dec6ec0426c88c64?hl=en
* different rounding behavior with float and double - 10 messages, 7 authors
http://groups.google.com/group/comp.lang.c++/t/05d32024f4d7a3b9?hl=en
* Friendly GUI for windows building? - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/c865fa27ccf9e327?hl=en
==============================================================================
TOPIC: Overloaded template resolution
http://groups.google.com/group/comp.lang.c++/t/16d19f355b1d27b4?hl=en
==============================================================================
== 1 of 1 ==
Date: Wed, Jan 8 2014 1:51 am
From: Öö Tiib
On Tuesday, 7 January 2014 06:01:48 UTC+2, somenath wrote:
> While going through the book C++ Primer (Third edition) I came across
> the following code from the book.
Will you post it every day now? Yes, it is a defect in book. All books contain
defects and some examples do not even compile. It is anyway good book.
So contact the authors if you want them to fix the defect.
==============================================================================
TOPIC: C++ standards committee looking at adding Cairo to the C++ standard
http://groups.google.com/group/comp.lang.c++/t/0b3c6e40a26c7051?hl=en
==============================================================================
== 1 of 10 ==
Date: Wed, Jan 8 2014 5:53 am
From: Jorgen Grahn
On Tue, 2014-01-07, Ian Collins wrote:
> Stefan Ram wrote:
>> Ian Collins <ian-news@hotmail.com> writes:
>>> That's correct. I can't see how adding something to the standard makes
>>> it easier to teach. Whether a widget is a std::widget or one from a
>>
>> ... non-standard ...
>>
>>> library, it is still a widget.
>>
>> When something is announced as a �C++ course�, it is easier to
>> teach what actually /is/ part of C++, because people expect this
>> and also I myself deem this to be honest.
>
> But you aren't teaching the library, you are using a part of it to
> illustrate a concept.
When I was a student, it was not uncommon to have exercises based on
some library or other ready-made code. It was usually written by the
teacher or someone at the staff, and explicitly crude and simple, not
enough for real-world use.
E.g. we got the parser and the virtual machine/interpreter for free
when we did the compiler course and were supposed to focus on code
generation. We got a nice little railroad simulator (graphical, with
bells and whistles) when doing the concurrency course. And so on.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
== 2 of 10 ==
Date: Wed, Jan 8 2014 7:40 pm
From: Ian Collins
Jorgen Grahn wrote:
> On Tue, 2014-01-07, Ian Collins wrote:
>>
>> In most of my projects, they are the documentation (and implementation)
>> step between the user stories and the code.
>
> I wonder if I would find them /useful/ as documentation too ... are
> any of these projects publicly available so I could take a look?
I'm afraid not.
I try to name my tests so they document the behaviour of the code. The
tests them selves act as both detailed descriptions and examples of how
to use the code. I think this is much easier to do well if the tests
are written first.
>> Unlike JavaDoc style
>> comments, they are always up to date!
>
> Yeah, well ... I don't understand what's so hard about keeping
> documentation up to date. I frequently see people let it slip, and I
> cannot figure out why. Incompetence?
Usually time pressure!
--
Ian Collins
== 3 of 10 ==
Date: Wed, Jan 8 2014 11:54 pm
From: Rui Maciel
Stefan Ram wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>>Teach them how things are done in the real world: pick a library and use
>>it.
>
> What works in the real world does not always work in the
> classroom. First, it does not even always work in the real
> world (many software project fail, are cancelled, or overdue).
I never heard of any case of a project failing due to having adopted a GUI toolkit which wasn't
included in an international standard.
> Next, the classes are already much too short to teach most
> of what is in the standard C++, so they only teach a selection.
> Teaching a »picked library« means that there will be even
> less time to teach C++ proper. While some students might
> like this, others might be alienated by it.
I don't see how you get more teaching time by adding a component to the C++ standard.
Rui Maciel
== 4 of 10 ==
Date: Thurs, Jan 9 2014 12:06 am
From: Rui Maciel
Öö Tiib wrote:
> I do not understand. Are you saying that first impression is irrelevant?
How many people got their first impression from C++ by reading the unreleased draft of the ISO
standard currently in development? Because it appears that so far with regards to first
impressions the language has been doing great so far.
> My point was that C++ toolset leaves sad first impression as state of art.
If you believe that standardizing GUI toolkits has anything to do with state of the art then
your concept is not only outdated by a decade or two but it also ignores history.
> C++ standard is guideline for people writing C++ compilers and standard
> library implementations so it has everything to do with improving that
> toolset.
Surely you must be aware that it's possible to develop components for C++ without having them
included in an ISO standard.
Rui maciel
== 5 of 10 ==
Date: Thurs, Jan 9 2014 12:12 am
From: Rui Maciel
Stefan Ram wrote:
> Ian Collins <ian-news@hotmail.com> writes:
>>That's correct. I can't see how adding something to the standard makes
>>it easier to teach. Whether a widget is a std::widget or one from a
>
> ... non-standard ...
>
>>library, it is still a widget.
>
> When something is announced as a »C++ course«, it is easier to
> teach what actually /is/ part of C++, because people expect this
> and also I myself deem this to be honest.
Do you believe that programs and/or libraries written in C++ aren't C++?
Rui Maciel
== 6 of 10 ==
Date: Thurs, Jan 9 2014 3:14 am
From: Öö Tiib
On Thursday, 9 January 2014 10:06:43 UTC+2, Rui Maciel wrote:
> Öö Tiib wrote:
>
> > I do not understand. Are you saying that first impression is irrelevant?
>
> How many people got their first impression from C++ by reading the unreleased draft of the ISO
> standard currently in development? Because it appears that so far with regards to first
> impressions the language has been doing great so far.
I repeat ... I don't understand what you are saying. Explain?
A: First impression does not matter. (Then lets agree to disagreement.)
B: First impression that C++ leaves is good. (Then lets agree to disagreement.)
C: Graphics can't attract nor impress. (Then lets agree to disagreement.)
D: C++ standard can do nothing to improve C++. (Then lets agree to disagreement.)
E: ... <- Please fill it.
Where did I write that standard is meant for reading by students? I did specify
standard's audience and you quoted it below.
> > My point was that C++ toolset leaves sad first impression as state of art.
>
> If you believe that standardizing GUI toolkits has anything to do with state of the art then
> your concept is not only outdated by a decade or two but it also ignores history.
Unimpressive state of compilers, standard library and tools of C++ is direct result of C++
standard not requiring features that can attract or impress from those people who should
read it. Historic issues continue being issues until repaired, decades do not matter.
> > C++ standard is guideline for people writing C++ compilers and standard
> > library implementations so it has everything to do with improving that
> > toolset.
>
> Surely you must be aware that it's possible to develop components for C++ without having them
> included in an ISO standard.
My awareness does not help at all with issue that I described. IOW it is irrelevant.
Every third newbie question is:
"what is good C++ GUI toolkit?" (first two questions are about books and tutorials)
Every second answer to that question is:
"Qt is more or less OK, but it is LGPL and it is corporately owned and it switches owners
every two years and it creates large binaries and the code of it is not really C++ and it
does take some serious hacking to get it to work on iOS or Android ... and so on."
Is it impressive?
== 7 of 10 ==
Date: Thurs, Jan 9 2014 3:57 am
From: Rui Maciel
Rui Maciel wrote:
> I never heard of any case of a project failing due to having adopted a GUI
> toolkit which wasn't included in an international standard.
Correction: a basic 2D drawing API.
Rui Maciel
== 8 of 10 ==
Date: Thurs, Jan 9 2014 10:20 am
From: Jorgen Grahn
On Thu, 2014-01-09, Ian Collins wrote:
> Jorgen Grahn wrote:
>> On Tue, 2014-01-07, Ian Collins wrote:
>>>
>>> In most of my projects, they are the documentation (and implementation)
>>> step between the user stories and the code.
>>
>> I wonder if I would find them /useful/ as documentation too ... are
>> any of these projects publicly available so I could take a look?
>
> I'm afraid not.
Ah, too bad.
> I try to name my tests so they document the behaviour of the code. The
> tests them selves act as both detailed descriptions and examples of how
> to use the code. I think this is much easier to do well if the tests
> are written first.
I can imagine that working to some extent ... especially if you
clearly separate "illustrative" tests and "tricky edge cases" tests.
But I suspect personality is involved too. For example, I learn much
better by reading about principles than from examples.
>>> Unlike JavaDoc style
>>> comments, they are always up to date!
>>
>> Yeah, well ... I don't understand what's so hard about keeping
>> documentation up to date. I frequently see people let it slip, and I
>> cannot figure out why. Incompetence?
>
> Usually time pressure!
Not when the documentation is five lines up from the place they
change. Then they're virtually shouting "I didn't bother to learn
about the /intentions/ behind this code before I changed it"[1].
Fortunately it's quite easy to catch this in review.
/Jorgen
[1] Once again, assuming the documentation is relevant to begin
with. If it's not, I'm liable to forget too.
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
== 9 of 10 ==
Date: Thurs, Jan 9 2014 2:28 pm
From: "Chris M. Thomasson"
> "Rui Maciel" wrote in message news:labt7p$co4$1@dont-email.me...
> It appears that Herb Sutter wants to add a 2D drawing library to the C++
> standard, and he is
> looking at libCairo as a base for this library.
> The link to the Cairo's mailing list:
> http://lists.cairographics.org/archives/cairo/2013-December/024858.html
> What are your thoughts on this?
Graphics for C++, Humm. Perhaps raw bitmaps?
Then teach the students how to program their own line and circle
plotting algorithms in C++. Then go for Bezier Curves, and on and
on. Turning math into visual representations can be a powerful
method of teaching...
IMVHO, starting to learn 2d graphics from "scratch" is the essence
of the power of C++.
;^)
== 10 of 10 ==
Date: Thurs, Jan 9 2014 6:44 pm
From: "Alf P. Steinbach"
On 09.01.2014 23:28, Chris M. Thomasson wrote:
>> "Rui Maciel" wrote in message news:labt7p$co4$1@dont-email.me...
>
>> It appears that Herb Sutter wants to add a 2D drawing library to the
>> C++ standard, and he is
>> looking at libCairo as a base for this library.
>
>> The link to the Cairo's mailing list:
>> http://lists.cairographics.org/archives/cairo/2013-December/024858.html
>
>> What are your thoughts on this?
>
> Graphics for C++, Humm. Perhaps raw bitmaps?
>
> Then teach the students how to program their own line and circle
> plotting algorithms in C++. Then go for Bezier Curves, and on and
> on. Turning math into visual representations can be a powerful
> method of teaching...
>
> IMVHO, starting to learn 2d graphics from "scratch" is the essence
> of the power of C++.
>
> ;^)
http://www.boost.org/doc/libs/1_55_0/libs/gil/doc/index.html
cheers & hth.,
- Alf
==============================================================================
TOPIC: Decoding GIF file in C? [Source code here]
http://groups.google.com/group/comp.lang.c++/t/dec6ec0426c88c64?hl=en
==============================================================================
== 1 of 4 ==
Date: Wed, Jan 8 2014 7:23 pm
From: kirannd1989@gmail.com
Hi..
i tried compiling this code but there are few undefined Macro/functions like MK_FP().
I am trying it on WIN32, VS2012.. i have made changes accordingly.
Is this solution dependent on any library.
Thanks in advance
On Monday, August 1, 1994 1:02:48 PM UTC+5:30, Cyborg wrote:
> In article <msm6.775622996@ra.msstate.edu> msm6@Ra.MsState.Edu (Muhammad Salman Mughal) writes:
> >
> >Hi there,
> >
> > I am desperately looking for a C code that could decode a GIF file
> > in DOS. Anybody out there who knows how to do it? I will really
> > appreciate any help.
> >
>
>
> The following code is based on a LZW decoder originally coded by Steven A.
> Bennett. All I did is write the code for parsing the GIF format, passing
> the approptiate data to the LZW decoder and writing the code for displaying
> the data on the screen. Both 87a and 89a formats are accepted.
>
> Video BIOS must support VESA functions - the code selects a video mode
> whith a resolution just high enough to display the given GIF file. Max
> resolution is 1280x1024, pictures larger than this will be partially
> displayed. Interlaced GIFs are supported. Program was only tested on my
> video card (Cirrus 5428 VESA Local Bus). It was not intended for public
> release but since I've already written it and the guy i desperate...
>
> Compiles with Borland C++ v3.1
>
> ----------------------- chop here --------------------------
>
> /* Various error codes used by decoder
> * and my own routines... It's okay
> * for you to define whatever you want,
> * as long as it's negative... It will be
> * returned intact up the various subroutine
> * levels...
> */
> #define READ_ERROR -1
> #define WRITE_ERROR -2
> #define OPEN_ERROR -3
> #define CREATE_ERROR -4
> #define OUT_OF_MEMORY -5
> #define BAD_CODE_SIZE -6
>
> #define ISIZE 2048 // image line size
> #define BSIZE 256 // buffer size
> #define PSIZE 768 // pallette size
> #define NULL 0L
> #define MAX_CODES 4095
>
> #include <dos.h>
> #include <conio.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> /* Static variables */
> short curr_size; /* The current code size */
> short clear; /* Value for a clear code */
> short ending; /* Value for a ending code */
> short newcodes; /* First available code */
> short top_slot; /* Highest code for current size */
> short slot; /* Last read code */
>
> /* The following static variables are used
> * for seperating out codes
> */
> short navail_bytes = 0; /* # bytes left in block */
> short nbits_left = 0; /* # bits left in current byte */
> unsigned char b1; /* Current byte */
> unsigned char byte_buff[257]; /* Current block */
> unsigned char *pbytes; /* Pointer to next byte in block */
>
> /* The reason we have these separated like this instead of using
> * a structure like the original Wilhite code did, is because this
> * stuff generally produces significantly faster code when compiled...
> * This code is full of similar speedups... (For a good book on writing
> * C for speed or for space optimisation, see Efficient C by Tom Plum,
> * published by Plum-Hall Associates...)
> */
> unsigned char stack[MAX_CODES + 1]; /* Stack for storing pixels */
> unsigned char suffix[MAX_CODES + 1]; /* Suffix table */
> unsigned short prefix[MAX_CODES + 1]; /* Prefix linked list */
>
> long code_mask[13] = {
> 0x0000,
> 0x0001, 0x0003, 0x0007, 0x000F,
> 0x001F, 0x003F, 0x007F, 0x00FF,
> 0x01FF, 0x03FF, 0x07FF, 0x0FFF
> };
>
> // incremented each time an out of range code is read by the decoder
> int bad_code_count;
>
> unsigned char far *buffer=NULL; // file buffer
> unsigned char far *grgb=NULL; // global rgb table
> unsigned char far *lrgb=NULL; // local rgb table
> unsigned char far *pixels=NULL; // line of pixels to be displayed
> unsigned char far *vid=NULL; // ptr to start of graphics window
> unsigned char background=0; // background color index
> unsigned long offset=0; // offset into graphics window
> unsigned long piclen; // total screen size in pixels
> unsigned int realx; // real picture width
> unsigned int realy; // real picture height
> unsigned int xsize=0; // graphic width
> unsigned int ysize=0; // graphic height
> unsigned int win=0; // window number
> unsigned int granularity=0; // granularity of video window
> unsigned int group=0; // picture group (interlaced or not)
> FILE *fp; // file pointer
>
> /* int get_byte()
> * - This function is expected to return the next byte from
> * the GIF file or a negative number defined in ERRS.H
> */
> int get_byte(){
> unsigned char c;
>
> if(fscanf(fp, "%c", &c)==1)
> return((int)c);
> else
> return(READ_ERROR);
> }
>
> /* int out_line(unsigned char pixels[], int linelen)
> * - This function takes a full line of pixels (one byte per pixel) and
> * displays them (or does whatever your program wants with them...). It
> * should return zero, or negative if an error or some other event occurs
> * which would require aborting the decode process... Note that the length
> * passed will almost always be equal to the line length passed to the
> * decoder function, with the sole exception occurring when an ending code
> * occurs in an odd place in the GIF file... In any case, linelen will be
> * equal to the number of pixels passed...
> */
> int out_line(unsigned char *pixels, int linelen){
> unsigned long segment;
>
> segment=offset&(unsigned long)(granularity-1);
>
> // put pixels on screen
> memmove(vid+segment, pixels, linelen);
> memset(vid+segment+linelen, background, xsize-linelen);
> switch (group) {
> case 0:
> offset+=xsize;
> break;
> case 1:
> offset+=xsize*8;
> if(offset>=piclen){
> group++;
> offset=xsize*4;
> }
> break;
> case 2:
> offset+=xsize*8;
> if(offset>=piclen){
> group++;
> offset=xsize*2;
> }
> break;
> case 3:
> offset+=xsize*4;
> if(offset>=piclen){
> group++;
> offset=xsize;
> }
> break;
> case 4:
> offset+=xsize*2;
> break;
> default:
> break;
> }
>
> // if we've run over a window granularity border, move window position
> if((offset>>12)!=win){
> win=offset>>12;
> asm pusha
> asm mov ax, 0x4f05
> asm mov bx, 0x0000
> asm mov dx, win
> asm int 0x10
> asm popa
> }
> return(1);
> }
>
>
> /* This function initializes the decoder for reading a new image.
> */
> static short init_exp(short size)
> {
> curr_size = size + 1;
> top_slot = 1 << curr_size;
> clear = 1 << size;
> ending = clear + 1;
> slot = newcodes = ending + 1;
> navail_bytes = nbits_left = 0;
> return(0);
> }
>
> /* get_next_code()
> * - gets the next code from the GIF file. Returns the code, or else
> * a negative number in case of file errors...
> */
> static short get_next_code()
> {
> short i, x;
> unsigned long ret;
>
> if (nbits_left == 0)
> {
> if (navail_bytes <= 0)
> {
>
> /* Out of bytes in current block, so read next block
> */
> pbytes = byte_buff;
> if ((navail_bytes = get_byte()) < 0)
> return(navail_bytes);
> else if (navail_bytes)
> {
> for (i = 0; i < navail_bytes; ++i)
> {
> if ((x = get_byte()) < 0)
> return(x);
> byte_buff[i] = x;
> }
> }
> }
> b1 = *pbytes++;
> nbits_left = 8;
> --navail_bytes;
> }
>
> ret = b1 >> (8 - nbits_left);
> while (curr_size > nbits_left)
> {
> if (navail_bytes <= 0)
> {
>
> /* Out of bytes in current block, so read next block
> */
> pbytes = byte_buff;
> if ((navail_bytes = get_byte()) < 0)
> return(navail_bytes);
> else if (navail_bytes)
> {
> for (i = 0; i < navail_bytes; ++i)
> {
> if ((x = get_byte()) < 0)
> return(x);
> byte_buff[i] = x;
> }
> }
> }
> b1 = *pbytes++;
> ret |= b1 << nbits_left;
> nbits_left += 8;
> --navail_bytes;
> }
> nbits_left -= curr_size;
> ret &= code_mask[curr_size];
> return((short)(ret));
> }
>
> /* DECODE.C - An LZW decoder for GIF
> *
> * Copyright (C) 1987, by Steven A. Bennett
> *
> * Permission is given by the author to freely redistribute and include
> * this code in any program as long as this credit is given where due.
> *
> * In accordance with the above, I want to credit Steve Wilhite who wrote
> * the code which this is heavily inspired by...
> *
> * GIF and 'Graphics Interchange Format' are trademarks (tm) of
> * Compuserve, Incorporated, an H&R Block Company.
> *
> * Release Notes: This file contains a decoder routine for GIF images
> * which is similar, structurally, to the original routine by Steve Wilhite.
> * It is, however, somewhat noticably faster in most cases.
> *
> * short decode(linewidth)
> * short linewidth; * Pixels per line of image *
> *
> * - This function decodes an LZW image, according to the method used
> * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded
> * will generate a call to out_line(), which is a user specific function
> * to display a line of pixels. The function gets it's codes from
> * get_next_code() which is responsible for reading blocks of data and
> * seperating them into the proper size codes. Finally, get_byte() is
> * the global routine to read the next byte from the GIF file.
> *
> * It is generally a good idea to have linewidth correspond to the actual
> * width of a line (as specified in the Image header) to make your own
> * code a bit simpler, but it isn't absolutely necessary.
> *
> * Returns: 0 if successful, else negative. (See ERRS.H)
> *
> */
>
> short decode(short linewidth)
> {
> register unsigned char *sp, *bufptr;
> unsigned char *buf;
> register short code, fc, oc, bufcnt;
> short c, size, ret;
>
> /* Initialize for decoding a new image...
> */
> if ((size = get_byte()) < 0)
> return(size);
> if (size < 2 || 9 < size)
> return(BAD_CODE_SIZE);
> init_exp(size);
>
> /* Initialize in case they forgot to put in a clear code.
> * (This shouldn't happen, but we'll try and decode it anyway...)
> */
> oc = fc = 0;
>
> /* Allocate space for the decode buffer
> */
> if ((buf = (unsigned char *)malloc(linewidth + 1)) == NULL)
> return(OUT_OF_MEMORY);
>
> /* Set up the stack pointer and decode buffer pointer
> */
> sp = stack;
> bufptr = buf;
> bufcnt = linewidth;
>
> /* This is the main loop. For each code we get we pass through the
> * linked list of prefix codes, pushing the corresponding "character" for
> * each code onto the stack. When the list reaches a single "character"
> * we push that on the stack too, and then start unstacking each
> * character for output in the correct order. Special handling is
> * included for the clear code, and the whole thing ends when we get
> * an ending code.
> */
> while ((c = get_next_code()) != ending)
> {
>
> /* If we had a file error, return without completing the decode
> */
> if (c < 0)
> {
> free(buf);
> return(0);
> }
>
> /* If the code is a clear code, reinitialize all necessary items.
> */
> if (c == clear)
> {
> curr_size = size + 1;
> slot = newcodes;
> top_slot = 1 << curr_size;
>
> /* Continue reading codes until we get a non-clear code
> * (Another unlikely, but possible case...)
> */
> while ((c = get_next_code()) == clear)
> ;
>
> /* If we get an ending code immediately after a clear code
> * (Yet another unlikely case), then break out of the loop.
> */
> if (c == ending)
> break;
>
> /* Finally, if the code is beyond the range of already set codes,
> * (This one had better NOT happen... I have no idea what will
> * result from this, but I doubt it will look good...) then set it
> * to color zero.
> */
> if (c >= slot)
> c = 0;
>
> oc = fc = c;
>
> /* And let us not forget to put the char into the buffer... And
> * if, on the off chance, we were exactly one pixel from the end
> * of the line, we have to send the buffer to the out_line()
> * routine...
> */
> *bufptr++ = c;
> if (--bufcnt == 0)
> {
> if ((ret = out_line(buf, linewidth)) < 0)
> {
> free(buf);
> return(ret);
> }
> bufptr = buf;
> bufcnt = linewidth;
> }
> }
> else
> {
>
> /* In this case, it's not a clear code or an ending code, so
> * it must be a code code... So we can now decode the code into
> * a stack of character codes. (Clear as mud, right?)
> */
> code = c;
>
> /* Here we go again with one of those off chances... If, on the
> * off chance, the code we got is beyond the range of those already
> * set up (Another thing which had better NOT happen...) we trick
> * the decoder into thinking it actually got the last code read.
> * (Hmmn... I'm not sure why this works... But it does...)
> */
> if (code >= slot)
> {
> if (code > slot)
> ++bad_code_count;
> code = oc;
> *sp++ = fc;
> }
>
> /* Here we scan back along the linked list of prefixes, pushing
> * helpless characters (ie. suffixes) onto the stack as we do so.
> */
> while (code >= newcodes)
> {
> *sp++ = suffix[code];
> code = prefix[code];
> }
>
> /* Push the last character on the stack, and set up the new
> * prefix and suffix, and if the required slot number is greater
> * than that allowed by the current bit size, increase the bit
> * size. (NOTE - If we are all full, we *don't* save the new
> * suffix and prefix... I'm not certain if this is correct...
> * it might be more proper to overwrite the last code...
> */
> *sp++ = code;
> if (slot < top_slot)
> {
> suffix[slot] = fc = code;
> prefix[slot++] = oc;
> oc = c;
> }
> if (slot >= top_slot)
> if (curr_size < 12)
> {
> top_slot <<= 1;
> ++curr_size;
> }
>
> /* Now that we've pushed the decoded string (in reverse order)
> * onto the stack, lets pop it off and put it into our decode
> * buffer... And when the decode buffer is full, write another
> * line...
> */
> while (sp > stack)
> {
> *bufptr++ = *(--sp);
> if (--bufcnt == 0)
> {
> if ((ret = out_line(buf, linewidth)) < 0)
> {
> free(buf);
> return(ret);
> }
> bufptr = buf;
> bufcnt = linewidth;
> }
> }
> }
> }
> ret = 0;
> if (bufcnt != linewidth)
> ret = out_line(buf, (linewidth - bufcnt));
> free(buf);
> return(ret);
> }
>
>
> // this function is called just before program exits
> void cleanup(void){
> // free any allocated resources
> if(fp!=NULL)
> fclose(fp);
> if(buffer!=NULL)
> free(buffer);
> if(grgb!=NULL)
> free(grgb);
> if(lrgb!=NULL)
> free(lrgb);
> if(pixels!=NULL)
> free(pixels);
> }
>
> void main(int argc, char **argv){
> unsigned int gctsize=0, lctsize=0, mode;
> int i;
>
> // set bad codes encountered to zero
> bad_code_count=0;
>
> // set function to be called on exit
> if(atexit(cleanup))
> exit(0);
>
> // exit if no file given
> if (argc<2){
> printf("Usage: %s gif_file\n", argv[0]);
> exit(0);
> }
>
> // try to open file
> if((fp=fopen(argv[1], "rb"))==NULL){
> printf("Failed to open file.\n");
> exit(0);
> }
>
> // allocate buffers
> buffer=(unsigned char *)malloc(BSIZE);
> pixels=(unsigned char *)malloc(ISIZE);
> grgb =(unsigned char *)malloc(PSIZE);
> lrgb =(unsigned char *)malloc(PSIZE);
> if((grgb==NULL) || (lrgb==NULL) || (pixels==NULL) || (buffer==NULL)){
> printf("Not enough memory.\n");
> exit(0);
> }
>
> fread(buffer, 1, 6, fp);
> // test file for valid GIF signature
> if(memcmp(buffer, "GIF", 3)!=0){
> printf("Not a GIF file.\n");
> exit(0);
> }
> // test file for version number
> if((memcmp(buffer+3, "87a", 3)!=0) && (memcmp(buffer+3, "89a", 3)!=0)){
> printf("Unsuported GIF version. Hit a key to decode anyway.\n");
> getch();
> }
>
> // read logical screen descriptor
> fread(buffer, 1, 7, fp);
>
> // test for global color table presence
> if(*(buffer+4)&0x80){
> // compute global color table size
> gctsize=1<<((*(buffer+4)&0x07) + 1);
> // read global color table into buffer
> fread(grgb, 1, gctsize*3, fp);
> // adjust colors to crappy 6-bit PC-DAC values
> for(i=0; i<gctsize*3; i++)
> *(grgb+i)>>=2;
> }
> // get background color index
> background=*(buffer+5);
>
>
> // scan file for data blocks
> while((i=get_byte())>0) {
> // in end of GIF marker encountered then exit
> if(i==0x3b)
> exit(0);
> // test for extentions
> if(i==0x21){
> if( (i=get_byte()) < 0 )
> exit(0);
> // if graphic color extention present or
> // coment extention present or
> // plain text extention present or
> // application extention present then skip it
> if( (i==0x01) || (i==0xf9) || (i==0xfe) || (i==0xff)){
> while((i=get_byte())!=0){
> if(fread(buffer, 1, i, fp)!=i)
> exit(0);
> }
> }
> }
>
> // test for presence of image descriptor
> if(i==0x2c){
> // get image descriptor
> fread(buffer, 1, 9, fp);
> // interlaced flag is set or cleared accordingly
> if(*(buffer+8)&0x40)
> group=1;
> realx=xsize=*(buffer+4) | (*(buffer+5)<<8);
> realy=ysize=*(buffer+6) | (*(buffer+7)<<8);
> // test for presence of local color table
> if(*(buffer+8)&0x80){
> // compute local color table size
> lctsize=1<<((*(buffer+8)&0x07) + 1);
> // read local color table into buffer
> fread(lrgb, 1, lctsize*3, fp);
> // adjust colors to crappy 6-bit PC-DAC values
> for(i=0; i<gctsize*3; i++)
> *(lrgb+i)>>=2;
> }
>
> // choose a video mode that will just fit the image
> if((xsize<=640) && (ysize<=480)){
> mode=0x101; // VESA 640 x 480 x 256
> xsize=640;
> ysize=480;
> } else if ((xsize<=800) && (ysize<=600)){
> mode=0x103; // VESA 800 x 600 x 256
> xsize=800;
> ysize=600;
> } else if ((xsize<=1024) && (ysize<=768)){
> mode=0x105; // VESA 1024 x 768 x 256
> xsize=1024;
> ysize=768;
> } else {
> mode=0x107; // VESA 1280 x 1024 x 256
> xsize=1280;
> ysize=1024;
> }
>
> piclen=(unsigned long)xsize*(unsigned long)ysize;
> // get video mode info through VESA call
> asm pusha
> asm mov ax, 0x4f01
> asm mov cx, mode
> asm les di, buffer
> asm int 0x10
> asm mov i, ax
> asm popa
>
> if(i!=0x004f){
> printf("VESA video functions not available.\n");
> exit(0);
> }
> // if mode not supported, or not color, or not graphics then exit
> if((*buffer&0x19)!=0x19){
> printf("Required graphics mode is not available.\n");
> exit(0);
> }
>
> // if window does not exist or is not writable exit
> if((*(buffer+2)&0x05)!=0x05) {
> printf("Cannot access video RAM.\n");
> exit(0);
> }
>
> // calculate window granularity
> granularity=(*(buffer+4) | (*(buffer+5)<<8))<<10;
> // calculate pointer to video RAM start
> vid=(unsigned char *)MK_FP((*(buffer+8) | (*(buffer+9)<<8)), 0);
>
> // set VESA video mode
> asm pusha
> asm mov ax, 0x4f02
> asm mov bx, mode
> asm int 0x10
> asm popa
>
> // set color table if present
> if(lctsize){
> // scope of local color table is local so once used it's gone
> lctsize=0;
> asm pusha
> asm mov ax, 0x1012
> asm mov bx, 0x0000
> asm mov cx, 0x0100
> asm les dx, lrgb
> asm int 0x10
> asm popa
> } else if(gctsize){
> // if no local color table then set global color table if present
> asm pusha
> asm mov ax, 0x1012
> asm mov bx, 0x0000
> asm mov cx, 0x0100
> asm les dx, grgb
> asm int 0x10
> asm pop es
> asm popa
> }
>
> // decode and display graphic
> decode(realx);
> // wait for key press
> getch();
>
> // set default text mode
> asm mov ax, 0x0003
> asm int 0x10
> }
> }
>
> // exit to dos
> exit(0);
> }
>
> -------------- chop here -------------------
>
> --
> +-----------------------------+-----------------------------------------------+
> | Alex Ivopol | If you love something set it free. If it |
> | cyborg@akeake.its.vuw.ac.nz | doesn't come back, hunt it down and kill it. |
> +-----------------------------+-----------------------------------------------+
== 2 of 4 ==
Date: Wed, Jan 8 2014 7:33 pm
From: Ian Collins
kirannd1989@gmail.com wrote:
> Hi..
> i tried compiling this code but there are few undefined Macro/functions like MK_FP().
> I am trying it on WIN32, VS2012.. i have made changes accordingly.
> Is this solution dependent on any library.
> Thanks in advance
>
>
> On Monday, August 1, 1994 1:02:48 PM UTC+5:30, Cyborg wrote:
Are you going for the record for the oldest post to reply to?
--
Ian Collins
== 3 of 4 ==
Date: Wed, Jan 8 2014 10:05 pm
From: Johann Klammer
kirannd1989@gmail.com wrote:
> Hi..
> i tried compiling this code but there are few undefined Macro/functions like MK_FP().
> I am trying it on WIN32, VS2012.. i have made changes accordingly.
> Is this solution dependent on any library.
> Thanks in advance
>
>
> On Monday, August 1, 1994 1:02:48 PM UTC+5:30, Cyborg wrote:
>> In article<msm6.775622996@ra.msstate.edu> msm6@Ra.MsState.Edu (Muhammad Salman Mughal) writes:
>>>
>>> Hi there,
>>>
>>> I am desperately looking for a C code that could decode a GIF file
>>> in DOS. Anybody out there who knows how to do it? I will really
>>> appreciate any help.
>>>
>>
>>
>> The following code is based on a LZW decoder originally coded by Steven A.
>> Bennett. All I did is write the code for parsing the GIF format, passing
>> the approptiate data to the LZW decoder and writing the code for displaying
>> the data on the screen. Both 87a and 89a formats are accepted.
>>
>> Video BIOS must support VESA functions - the code selects a video mode
>> whith a resolution just high enough to display the given GIF file. Max
>> resolution is 1280x1024, pictures larger than this will be partially
>> displayed. Interlaced GIFs are supported. Program was only tested on my
>> video card (Cirrus 5428 VESA Local Bus). It was not intended for public
>> release but since I've already written it and the guy i desperate...
>>
>> Compiles with Borland C++ v3.1
>>
>> ----------------------- chop here --------------------------
>>
>> /* Various error codes used by decoder
>> * and my own routines... It's okay
>> * for you to define whatever you want,
>> * as long as it's negative... It will be
>> * returned intact up the various subroutine
>> * levels...
>> */
>> #define READ_ERROR -1
>> #define WRITE_ERROR -2
>> #define OPEN_ERROR -3
>> #define CREATE_ERROR -4
>> #define OUT_OF_MEMORY -5
>> #define BAD_CODE_SIZE -6
>>
>> #define ISIZE 2048 // image line size
>> #define BSIZE 256 // buffer size
>> #define PSIZE 768 // pallette size
>> #define NULL 0L
>> #define MAX_CODES 4095
>>
>> #include<dos.h>
>> #include<conio.h>
>> #include<stdio.h>
>> #include<stdlib.h>
>> #include<string.h>
>>
>> /* Static variables */
>> short curr_size; /* The current code size */
>> short clear; /* Value for a clear code */
>> short ending; /* Value for a ending code */
>> short newcodes; /* First available code */
>> short top_slot; /* Highest code for current size */
>> short slot; /* Last read code */
>>
>> /* The following static variables are used
>> * for seperating out codes
>> */
>> short navail_bytes = 0; /* # bytes left in block */
>> short nbits_left = 0; /* # bits left in current byte */
>> unsigned char b1; /* Current byte */
>> unsigned char byte_buff[257]; /* Current block */
>> unsigned char *pbytes; /* Pointer to next byte in block */
>>
>> /* The reason we have these separated like this instead of using
>> * a structure like the original Wilhite code did, is because this
>> * stuff generally produces significantly faster code when compiled...
>> * This code is full of similar speedups... (For a good book on writing
>> * C for speed or for space optimisation, see Efficient C by Tom Plum,
>> * published by Plum-Hall Associates...)
>> */
>> unsigned char stack[MAX_CODES + 1]; /* Stack for storing pixels */
>> unsigned char suffix[MAX_CODES + 1]; /* Suffix table */
>> unsigned short prefix[MAX_CODES + 1]; /* Prefix linked list */
>>
>> long code_mask[13] = {
>> 0x0000,
>> 0x0001, 0x0003, 0x0007, 0x000F,
>> 0x001F, 0x003F, 0x007F, 0x00FF,
>> 0x01FF, 0x03FF, 0x07FF, 0x0FFF
>> };
>>
>> // incremented each time an out of range code is read by the decoder
>> int bad_code_count;
>>
>> unsigned char far *buffer=NULL; // file buffer
>> unsigned char far *grgb=NULL; // global rgb table
>> unsigned char far *lrgb=NULL; // local rgb table
>> unsigned char far *pixels=NULL; // line of pixels to be displayed
>> unsigned char far *vid=NULL; // ptr to start of graphics window
>> unsigned char background=0; // background color index
>> unsigned long offset=0; // offset into graphics window
>> unsigned long piclen; // total screen size in pixels
>> unsigned int realx; // real picture width
>> unsigned int realy; // real picture height
>> unsigned int xsize=0; // graphic width
>> unsigned int ysize=0; // graphic height
>> unsigned int win=0; // window number
>> unsigned int granularity=0; // granularity of video window
>> unsigned int group=0; // picture group (interlaced or not)
>> FILE *fp; // file pointer
>>
>> /* int get_byte()
>> * - This function is expected to return the next byte from
>> * the GIF file or a negative number defined in ERRS.H
>> */
>> int get_byte(){
>> unsigned char c;
>>
>> if(fscanf(fp, "%c",&c)==1)
>> return((int)c);
>> else
>> return(READ_ERROR);
>> }
>>
>> /* int out_line(unsigned char pixels[], int linelen)
>> * - This function takes a full line of pixels (one byte per pixel) and
>> * displays them (or does whatever your program wants with them...). It
>> * should return zero, or negative if an error or some other event occurs
>> * which would require aborting the decode process... Note that the length
>> * passed will almost always be equal to the line length passed to the
>> * decoder function, with the sole exception occurring when an ending code
>> * occurs in an odd place in the GIF file... In any case, linelen will be
>> * equal to the number of pixels passed...
>> */
>> int out_line(unsigned char *pixels, int linelen){
>> unsigned long segment;
>>
>> segment=offset&(unsigned long)(granularity-1);
>>
>> // put pixels on screen
>> memmove(vid+segment, pixels, linelen);
>> memset(vid+segment+linelen, background, xsize-linelen);
>> switch (group) {
>> case 0:
>> offset+=xsize;
>> break;
>> case 1:
>> offset+=xsize*8;
>> if(offset>=piclen){
>> group++;
>> offset=xsize*4;
>> }
>> break;
>> case 2:
>> offset+=xsize*8;
>> if(offset>=piclen){
>> group++;
>> offset=xsize*2;
>> }
>> break;
>> case 3:
>> offset+=xsize*4;
>> if(offset>=piclen){
>> group++;
>> offset=xsize;
>> }
>> break;
>> case 4:
>> offset+=xsize*2;
>> break;
>> default:
>> break;
>> }
>>
>> // if we've run over a window granularity border, move window position
>> if((offset>>12)!=win){
>> win=offset>>12;
>> asm pusha
>> asm mov ax, 0x4f05
>> asm mov bx, 0x0000
>> asm mov dx, win
>> asm int 0x10
>> asm popa
>> }
>> return(1);
>> }
>>
>>
>> /* This function initializes the decoder for reading a new image.
>> */
>> static short init_exp(short size)
>> {
>> curr_size = size + 1;
>> top_slot = 1<< curr_size;
>> clear = 1<< size;
>> ending = clear + 1;
>> slot = newcodes = ending + 1;
>> navail_bytes = nbits_left = 0;
>> return(0);
>> }
>>
>> /* get_next_code()
>> * - gets the next code from the GIF file. Returns the code, or else
>> * a negative number in case of file errors...
>> */
>> static short get_next_code()
>> {
>> short i, x;
>> unsigned long ret;
>>
>> if (nbits_left == 0)
>> {
>> if (navail_bytes<= 0)
>> {
>>
>> /* Out of bytes in current block, so read next block
>> */
>> pbytes = byte_buff;
>> if ((navail_bytes = get_byte())< 0)
>> return(navail_bytes);
>> else if (navail_bytes)
>> {
>> for (i = 0; i< navail_bytes; ++i)
>> {
>> if ((x = get_byte())< 0)
>> return(x);
>> byte_buff[i] = x;
>> }
>> }
>> }
>> b1 = *pbytes++;
>> nbits_left = 8;
>> --navail_bytes;
>> }
>>
>> ret = b1>> (8 - nbits_left);
>> while (curr_size> nbits_left)
>> {
>> if (navail_bytes<= 0)
>> {
>>
>> /* Out of bytes in current block, so read next block
>> */
>> pbytes = byte_buff;
>> if ((navail_bytes = get_byte())< 0)
>> return(navail_bytes);
>> else if (navail_bytes)
>> {
>> for (i = 0; i< navail_bytes; ++i)
>> {
>> if ((x = get_byte())< 0)
>> return(x);
>> byte_buff[i] = x;
>> }
>> }
>> }
>> b1 = *pbytes++;
>> ret |= b1<< nbits_left;
>> nbits_left += 8;
>> --navail_bytes;
>> }
>> nbits_left -= curr_size;
>> ret&= code_mask[curr_size];
>> return((short)(ret));
>> }
>>
>> /* DECODE.C - An LZW decoder for GIF
>> *
>> * Copyright (C) 1987, by Steven A. Bennett
>> *
>> * Permission is given by the author to freely redistribute and include
>> * this code in any program as long as this credit is given where due.
>> *
>> * In accordance with the above, I want to credit Steve Wilhite who wrote
>> * the code which this is heavily inspired by...
>> *
>> * GIF and 'Graphics Interchange Format' are trademarks (tm) of
>> * Compuserve, Incorporated, an H&R Block Company.
>> *
>> * Release Notes: This file contains a decoder routine for GIF images
>> * which is similar, structurally, to the original routine by Steve Wilhite.
>> * It is, however, somewhat noticably faster in most cases.
>> *
>> * short decode(linewidth)
>> * short linewidth; * Pixels per line of image *
>> *
>> * - This function decodes an LZW image, according to the method used
>> * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded
>> * will generate a call to out_line(), which is a user specific function
>> * to display a line of pixels. The function gets it's codes from
>> * get_next_code() which is responsible for reading blocks of data and
>> * seperating them into the proper size codes. Finally, get_byte() is
>> * the global routine to read the next byte from the GIF file.
>> *
>> * It is generally a good idea to have linewidth correspond to the actual
>> * width of a line (as specified in the Image header) to make your own
>> * code a bit simpler, but it isn't absolutely necessary.
>> *
>> * Returns: 0 if successful, else negative. (See ERRS.H)
>> *
>> */
>>
>> short decode(short linewidth)
>> {
>> register unsigned char *sp, *bufptr;
>> unsigned char *buf;
>> register short code, fc, oc, bufcnt;
>> short c, size, ret;
>>
>> /* Initialize for decoding a new image...
>> */
>> if ((size = get_byte())< 0)
>> return(size);
>> if (size< 2 || 9< size)
>> return(BAD_CODE_SIZE);
>> init_exp(size);
>>
>> /* Initialize in case they forgot to put in a clear code.
>> * (This shouldn't happen, but we'll try and decode it anyway...)
>> */
>> oc = fc = 0;
>>
>> /* Allocate space for the decode buffer
>> */
>> if ((buf = (unsigned char *)malloc(linewidth + 1)) == NULL)
>> return(OUT_OF_MEMORY);
>>
>> /* Set up the stack pointer and decode buffer pointer
>> */
>> sp = stack;
>> bufptr = buf;
>> bufcnt = linewidth;
>>
>> /* This is the main loop. For each code we get we pass through the
>> * linked list of prefix codes, pushing the corresponding "character" for
>> * each code onto the stack. When the list reaches a single "character"
>> * we push that on the stack too, and then start unstacking each
>> * character for output in the correct order. Special handling is
>> * included for the clear code, and the whole thing ends when we get
>> * an ending code.
>> */
>> while ((c = get_next_code()) != ending)
>> {
>>
>> /* If we had a file error, return without completing the decode
>> */
>> if (c< 0)
>> {
>> free(buf);
>> return(0);
>> }
>>
>> /* If the code is a clear code, reinitialize all necessary items.
>> */
>> if (c == clear)
>> {
>> curr_size = size + 1;
>> slot = newcodes;
>> top_slot = 1<< curr_size;
>>
>> /* Continue reading codes until we get a non-clear code
>> * (Another unlikely, but possible case...)
>> */
>> while ((c = get_next_code()) == clear)
>> ;
>>
>> /* If we get an ending code immediately after a clear code
>> * (Yet another unlikely case), then break out of the loop.
>> */
>> if (c == ending)
>> break;
>>
>> /* Finally, if the code is beyond the range of already set codes,
>> * (This one had better NOT happen... I have no idea what will
>> * result from this, but I doubt it will look good...) then set it
>> * to color zero.
>> */
>> if (c>= slot)
>> c = 0;
>>
>> oc = fc = c;
>>
>> /* And let us not forget to put the char into the buffer... And
>> * if, on the off chance, we were exactly one pixel from the end
>> * of the line, we have to send the buffer to the out_line()
>> * routine...
>> */
>> *bufptr++ = c;
>> if (--bufcnt == 0)
>> {
>> if ((ret = out_line(buf, linewidth))< 0)
>> {
>> free(buf);
>> return(ret);
>> }
>> bufptr = buf;
>> bufcnt = linewidth;
>> }
>> }
>> else
>> {
>>
>> /* In this case, it's not a clear code or an ending code, so
>> * it must be a code code... So we can now decode the code into
>> * a stack of character codes. (Clear as mud, right?)
>> */
>> code = c;
>>
>> /* Here we go again with one of those off chances... If, on the
>> * off chance, the code we got is beyond the range of those already
>> * set up (Another thing which had better NOT happen...) we trick
>> * the decoder into thinking it actually got the last code read.
>> * (Hmmn... I'm not sure why this works... But it does...)
>> */
>> if (code>= slot)
>> {
>> if (code> slot)
>> ++bad_code_count;
>> code = oc;
>> *sp++ = fc;
>> }
>>
>> /* Here we scan back along the linked list of prefixes, pushing
>> * helpless characters (ie. suffixes) onto the stack as we do so.
>> */
>> while (code>= newcodes)
>> {
>> *sp++ = suffix[code];
>> code = prefix[code];
>> }
>>
>> /* Push the last character on the stack, and set up the new
>> * prefix and suffix, and if the required slot number is greater
>> * than that allowed by the current bit size, increase the bit
>> * size. (NOTE - If we are all full, we *don't* save the new
>> * suffix and prefix... I'm not certain if this is correct...
>> * it might be more proper to overwrite the last code...
>> */
>> *sp++ = code;
>> if (slot< top_slot)
>> {
>> suffix[slot] = fc = code;
>> prefix[slot++] = oc;
>> oc = c;
>> }
>> if (slot>= top_slot)
>> if (curr_size< 12)
>> {
>> top_slot<<= 1;
>> ++curr_size;
>> }
>>
>> /* Now that we've pushed the decoded string (in reverse order)
>> * onto the stack, lets pop it off and put it into our decode
>> * buffer... And when the decode buffer is full, write another
>> * line...
>> */
>> while (sp> stack)
>> {
>> *bufptr++ = *(--sp);
>> if (--bufcnt == 0)
>> {
>> if ((ret = out_line(buf, linewidth))< 0)
>> {
>> free(buf);
>> return(ret);
>> }
>> bufptr = buf;
>> bufcnt = linewidth;
>> }
>> }
>> }
>> }
>> ret = 0;
>> if (bufcnt != linewidth)
>> ret = out_line(buf, (linewidth - bufcnt));
>> free(buf);
>> return(ret);
>> }
>>
>>
>> // this function is called just before program exits
>> void cleanup(void){
>> // free any allocated resources
>> if(fp!=NULL)
>> fclose(fp);
>> if(buffer!=NULL)
>> free(buffer);
>> if(grgb!=NULL)
>> free(grgb);
>> if(lrgb!=NULL)
>> free(lrgb);
>> if(pixels!=NULL)
>> free(pixels);
>> }
>>
>> void main(int argc, char **argv){
>> unsigned int gctsize=0, lctsize=0, mode;
>> int i;
>>
>> // set bad codes encountered to zero
>> bad_code_count=0;
>>
>> // set function to be called on exit
>> if(atexit(cleanup))
>> exit(0);
>>
>> // exit if no file given
>> if (argc<2){
>> printf("Usage: %s gif_file\n", argv[0]);
>> exit(0);
>> }
>>
>> // try to open file
>> if((fp=fopen(argv[1], "rb"))==NULL){
>> printf("Failed to open file.\n");
>> exit(0);
>> }
>>
>> // allocate buffers
>> buffer=(unsigned char *)malloc(BSIZE);
>> pixels=(unsigned char *)malloc(ISIZE);
>> grgb =(unsigned char *)malloc(PSIZE);
>> lrgb =(unsigned char *)malloc(PSIZE);
>> if((grgb==NULL) || (lrgb==NULL) || (pixels==NULL) || (buffer==NULL)){
>> printf("Not enough memory.\n");
>> exit(0);
>> }
>>
>> fread(buffer, 1, 6, fp);
>> // test file for valid GIF signature
>> if(memcmp(buffer, "GIF", 3)!=0){
>> printf("Not a GIF file.\n");
>> exit(0);
>> }
>> // test file for version number
>> if((memcmp(buffer+3, "87a", 3)!=0)&& (memcmp(buffer+3, "89a", 3)!=0)){
>> printf("Unsuported GIF version. Hit a key to decode anyway.\n");
>> getch();
>> }
>>
>> // read logical screen descriptor
>> fread(buffer, 1, 7, fp);
>>
>> // test for global color table presence
>> if(*(buffer+4)&0x80){
>> // compute global color table size
>> gctsize=1<<((*(buffer+4)&0x07) + 1);
>> // read global color table into buffer
>> fread(grgb, 1, gctsize*3, fp);
>> // adjust colors to crappy 6-bit PC-DAC values
>> for(i=0; i<gctsize*3; i++)
>> *(grgb+i)>>=2;
>> }
>> // get background color index
>> background=*(buffer+5);
>>
>>
>> // scan file for data blocks
>> while((i=get_byte())>0) {
>> // in end of GIF marker encountered then exit
>> if(i==0x3b)
>> exit(0);
>> // test for extentions
>> if(i==0x21){
>> if( (i=get_byte())< 0 )
>> exit(0);
>> // if graphic color extention present or
>> // coment extention present or
>> // plain text extention present or
>> // application extention present then skip it
>> if( (i==0x01) || (i==0xf9) || (i==0xfe) || (i==0xff)){
>> while((i=get_byte())!=0){
>> if(fread(buffer, 1, i, fp)!=i)
>> exit(0);
>> }
>> }
>> }
>>
>> // test for presence of image descriptor
>> if(i==0x2c){
>> // get image descriptor
>> fread(buffer, 1, 9, fp);
>> // interlaced flag is set or cleared accordingly
>> if(*(buffer+8)&0x40)
>> group=1;
>> realx=xsize=*(buffer+4) | (*(buffer+5)<<8);
>> realy=ysize=*(buffer+6) | (*(buffer+7)<<8);
>> // test for presence of local color table
>> if(*(buffer+8)&0x80){
>> // compute local color table size
>> lctsize=1<<((*(buffer+8)&0x07) + 1);
>> // read local color table into buffer
>> fread(lrgb, 1, lctsize*3, fp);
>> // adjust colors to crappy 6-bit PC-DAC values
>> for(i=0; i<gctsize*3; i++)
>> *(lrgb+i)>>=2;
>> }
>>
>> // choose a video mode that will just fit the image
>> if((xsize<=640)&& (ysize<=480)){
>> mode=0x101; // VESA 640 x 480 x 256
>> xsize=640;
>> ysize=480;
>> } else if ((xsize<=800)&& (ysize<=600)){
>> mode=0x103; // VESA 800 x 600 x 256
>> xsize=800;
>> ysize=600;
>> } else if ((xsize<=1024)&& (ysize<=768)){
>> mode=0x105; // VESA 1024 x 768 x 256
>> xsize=1024;
>> ysize=768;
>> } else {
>> mode=0x107; // VESA 1280 x 1024 x 256
>> xsize=1280;
>> ysize=1024;
>> }
>>
>> piclen=(unsigned long)xsize*(unsigned long)ysize;
>> // get video mode info through VESA call
>> asm pusha
>> asm mov ax, 0x4f01
>> asm mov cx, mode
>> asm les di, buffer
>> asm int 0x10
>> asm mov i, ax
>> asm popa
>>
>> if(i!=0x004f){
>> printf("VESA video functions not available.\n");
>> exit(0);
>> }
>> // if mode not supported, or not color, or not graphics then exit
>> if((*buffer&0x19)!=0x19){
>> printf("Required graphics mode is not available.\n");
>> exit(0);
>> }
>>
>> // if window does not exist or is not writable exit
>> if((*(buffer+2)&0x05)!=0x05) {
>> printf("Cannot access video RAM.\n");
>> exit(0);
>> }
>>
>> // calculate window granularity
>> granularity=(*(buffer+4) | (*(buffer+5)<<8))<<10;
>> // calculate pointer to video RAM start
>> vid=(unsigned char *)MK_FP((*(buffer+8) | (*(buffer+9)<<8)), 0);
>>
>> // set VESA video mode
>> asm pusha
>> asm mov ax, 0x4f02
>> asm mov bx, mode
>> asm int 0x10
>> asm popa
>>
>> // set color table if present
>> if(lctsize){
>> // scope of local color table is local so once used it's gone
>> lctsize=0;
>> asm pusha
>> asm mov ax, 0x1012
>> asm mov bx, 0x0000
>> asm mov cx, 0x0100
>> asm les dx, lrgb
>> asm int 0x10
>> asm popa
>> } else if(gctsize){
>> // if no local color table then set global color table if present
>> asm pusha
>> asm mov ax, 0x1012
>> asm mov bx, 0x0000
>> asm mov cx, 0x0100
>> asm les dx, grgb
>> asm int 0x10
>> asm pop es
>> asm popa
>> }
>>
>> // decode and display graphic
>> decode(realx);
>> // wait for key press
>> getch();
>>
>> // set default text mode
>> asm mov ax, 0x0003
>> asm int 0x10
>> }
>> }
>>
>> // exit to dos
>> exit(0);
>> }
>>
>> -------------- chop here -------------------
>>
>> --
>> +-----------------------------+-----------------------------------------------+
>> | Alex Ivopol | If you love something set it free. If it |
>> | cyborg@akeake.its.vuw.ac.nz | doesn't come back, hunt it down and kill it. |
>> +-----------------------------+-----------------------------------------------+
Dear people from the future,
The code does direct hardware access to gfx card(VESA for mode-setting
and output). The MK_FP is problematic, too(16 bit dos program). The
output is pallettized and 6 bits per components(r,g,b). You'll most
likely want 8. Aside from those details it might work alright. You will
need another way to actually display the decoded data. there have been
help files floating around the net documenting M$ win32 API. try those.
Also...
http://www.winprog.org/tutorial/
== 4 of 4 ==
Date: Wed, Jan 8 2014 10:27 pm
From: "Alf P. Steinbach"
On 09.01.2014 04:23, kirannd1989@gmail.com wrote:
> Hi..
> i tried compiling this code but there are few undefined Macro/functions like MK_FP().
> I am trying it on WIN32, VS2012.. i have made changes accordingly.
> Is this solution dependent on any library.
[snip early 1990's code]
No, the code is just very DOS-specific. It contains inline assembly for
a PC, with the program running with the processor in 8086 mode. In this
mode a logical address consists of a 16-bit offset and a 16-bit segment
selector. The segment selector could be implied, then taken from a
processor register. This (a 16-bit logical address specified as only
offset) was called a NEAR address. Alternatively the segment selector
could be explicitly specified, and this (a 32-bit logical address
specified as offset and selector) was called a FAR address.
Worth noting that a FAR address only specified 21 bits, because a
selector S always selected the logical segment starting at address 16*S.
MK_FP created a C language representation of a "far pointer".
There is nothing corresponding to that[1] in modern C or C++.
* * *
You may still be able to use the code, either directly in a DOS box (the
DOS emulator, not a Windows command interpreter instance) or by
replacing the DOS presentation with whatever you want.
Cheers & hth.,
- Alf
Notes:
[1] In still much used 32-bit C and C++ programming on the PC there is a
corresponding issue, namely that all addresses handled by C or C++
pointers are really just 32-bit offsets into a segment. The implied
segment selector can come from any relevant selector register because
the operating places the same selector value in all these registers (a
neat little trick). In order to access some Windows thread information
it's necessary to specify a different segment than the usual, namely the
one denoted by the FS register, if I recall correctly. To do this one
must delve down to the assembly language level.
==============================================================================
TOPIC: different rounding behavior with float and double
http://groups.google.com/group/comp.lang.c++/t/05d32024f4d7a3b9?hl=en
==============================================================================
== 1 of 10 ==
Date: Thurs, Jan 9 2014 1:46 am
From: Raymond Li
I have encountered a problem related to floating point rounding. I
googled a lot and there are many clear and helpful information. e.g.
http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
http://support.microsoft.com/kb/125056/en-hk
Although the urls have explained the cause, I need to find a practical
way to solve a rounding problem. My program has calculated a weighted
accumulation as 3.5. When the figure is rounded to nearest number, it
became 3 (but I want it to round up to 4). I understood it would be due
to approximation value of 3.5 as 3.49999...
I found a simple fix by using float instead of double. I list the
program below and wish someone could explain why using double would
incur the rounding problem while float would not. In the code below,
fun1() use float and the calculation is 'correct'. In fun2(), it uses
double and the figure 3.5 is rounded as 3.
Raymond
//######################
#include <cmath>
#include <iostream>
//using namespace std;
using std::cout;
using std::endl;
int fun1();
int fun2();
int main(int argc, char ** argv)
{
fun1();
fun2();
return 0;
}
int fun1()
{
float weighted=10.0;
float average=100.0;
float z[]=
{
4.0,
4.0,
4.0,
4.0,
4.0,
3.0,
3.0,
3.0,
2.0,
4.0
};
float total=0.0;
int i=0;
for (i=0;i<10;i++)
{
float item=z[i]*weighted/average;
total=total+item;
cout << i << " accumulate is " << total << endl;
// NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
}
float answer=round(total);
// NSLog(@"rounded is %f", answer);
cout << "rounded is " << answer << endl;
return 0;
}
int fun2()
{
double weighted=10.0;
double average=100.0;
double z[]=
{
4.0,
4.0,
4.0,
4.0,
4.0,
3.0,
3.0,
3.0,
2.0,
4.0
};
double total=0.0;
int i=0;
for (i=0;i<10;i++)
{
double item=z[i]*weighted/average;
total=total+item;
cout << i << " accumulate is " << total << endl;
// NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
}
double answer=round(total);
// NSLog(@"rounded is %f", answer);
cout << "rounded is " << answer << endl;
return 0;
}
0 accumulate is 0.4
1 accumulate is 0.8
2 accumulate is 1.2
3 accumulate is 1.6
4 accumulate is 2
5 accumulate is 2.3
6 accumulate is 2.6
7 accumulate is 2.9
8 accumulate is 3.1
9 accumulate is 3.5
rounded is 4
***(above is the version using float, 3.5 is rounded as 4) ***
0 accumulate is 0.4
1 accumulate is 0.8
2 accumulate is 1.2
3 accumulate is 1.6
4 accumulate is 2
5 accumulate is 2.3
6 accumulate is 2.6
7 accumulate is 2.9
8 accumulate is 3.1
9 accumulate is 3.5
rounded is 3
***(this version use double, 3.5 is rounded as 3) ***
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
== 2 of 10 ==
Date: Thurs, Jan 9 2014 3:48 am
From: "Alf P. Steinbach"
On 09.01.2014 10:46, Raymond Li wrote:
>
> My program has calculated a weighted
> accumulation as 3.5. When the figure is rounded to nearest number, it
> became 3 (but I want it to round up to 4). I understood it would be due
> to approximation value of 3.5 as 3.49999...
round(x) rounds to the /nearest/ integer value of the type.
When x is around 3.5, as in your case, very tiny differences can make 3
or 4 the nearest integer. These tiny differences can be, well,
different, for float and double types (the latter has double the
precision, roughly).
If you want to round to 1 decimal fractional digit, then simply do this:
round( 10*x )/10
Or you can define that as a function:
auto rounded( double x, int n_decimals = 2 )
-> double
{
double const pow_of_10 = pow( 10.0, n_decimals );
return round( pow_of_10*x )/pow_of_ten;
}
Now regarding the choice of data type I (strongly) suggest to use
double, because that's the default and least troublesome in C++.
For example, a literal such as 3.14 is a double, and C style functions
such as printf and scanf work with double values.
Cheers & hth.,
- Alf
== 3 of 10 ==
Date: Thurs, Jan 9 2014 4:21 am
From: ram@zedat.fu-berlin.de (Stefan Ram)
Raymond Li <faihk1@gmail.com> writes:
>I found a simple fix by using float instead of double. I list the
>program below and wish someone could explain why using double would
>incur the rounding problem while float would not. In the code below,
>fun1() use float and the calculation is 'correct'. In fun2(), it uses
>double and the figure 3.5 is rounded as 3.
In this special case, the result might be correct using
float, but on the average (for random double values as
input) double will be correct more often.
When the input is (2,3,3,3,4,4,4,4,4,4), the average is 35/10,
so a human can work out the result and see that it should
be rounded to 4, so that a result of 3 might be disturbing.
But in the general case, when the input consists of random
double values, a human computer cannot do much better than
an electronic computer using double.
The electronic computer could use integer fraction arithmetics
to handle such special cases as (2,3,3,3,4,4,4,4,4,4), where
division by powers of ten or similar divisions occur to get
exactly the result as a human and double arithmetics in all
other cases.
== 4 of 10 ==
Date: Thurs, Jan 9 2014 5:58 am
From: Richard Damon
On 1/9/14, 4:46 AM, Raymond Li wrote:
> I have encountered a problem related to floating point rounding. I
> googled a lot and there are many clear and helpful information. e.g.
>
> http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
> http://support.microsoft.com/kb/125056/en-hk
>
>
> Although the urls have explained the cause, I need to find a practical
> way to solve a rounding problem. My program has calculated a weighted
> accumulation as 3.5. When the figure is rounded to nearest number, it
> became 3 (but I want it to round up to 4). I understood it would be due
> to approximation value of 3.5 as 3.49999...
>
> I found a simple fix by using float instead of double. I list the
> program below and wish someone could explain why using double would
> incur the rounding problem while float would not. In the code below,
> fun1() use float and the calculation is 'correct'. In fun2(), it uses
> double and the figure 3.5 is rounded as 3.
>
> Raymond
>
>
This program is effectively calculating something like
.4 + .4 + .4 + .4 + .4 + .3 + .3 + .3 + .2 + .4
Note that none of these values can be exactly expresses as a float or
double so we get numerous round off errors.
If instead you computed it as
(4.0 + 4.0 + 4.0 + 4.0 + 4.0 + 3.0 + 3.0 + 3.0 + 2.0 + 4.0)/10.0
Then each number (having the value of a small integer) can be exactly
represented as a double, and the result will be exact (since the result
3.5 = 7/2 is an exact binary fraction, unlike 4/10)
You only notice this round off error because your input numbers and
weighting factors are "nice" numbers so you can mentally to the math
exactly. Since the answer is very near a discontinuity (the .5 break
point of round), the result is very sensitive to small errors in
calculation.
If the numbers were more realistically not so precisely "round" numbers,
you are much less apt to hit this sort of discontinuous behavior in a
noticeable way.
If the input numbers ARE expected to this sort of nice number, then you
need to be very careful how you do your math to avoid creating "not
nice" numbers along the way creating round of error. Not nice numbers
are numbers line .4 which aren't a reasonable integral multiple of a
power of 2 (note that 1 is a power of 2, being 2 to the 0th power, so
integral numbers are nice, decimal fractions are generally not nice,
unless they are things like .5, .25, .375, which are decimal equivalents
of simple binary fractions).
When you have "nice" numbers, you can add them, subtract them, or
multiply them (within reason) and stay "nice", dividing will likely
break nice, unless you are dividing by a power of 2, so algorithms that
maximize accuracy for "nice" numbers need to avoid dividing as much as
possible, and make it as late a possible.
== 5 of 10 ==
Date: Thurs, Jan 9 2014 6:14 am
From: Wouter van Ooijen
> This program is effectively calculating something like
>
> .4 + .4 + .4 + .4 + .4 + .3 + .3 + .3 + .2 + .4
>
> Note that none of these values can be exactly expresses as a float or
> double so we get numerous round off errors.
>
> If instead you computed it as
>
> (4.0 + 4.0 + 4.0 + 4.0 + 4.0 + 3.0 + 3.0 + 3.0 + 2.0 + 4.0)/10.0
>
> Then each number (having the value of a small integer) can be exactly
> represented as a double, and the result will be exact (since the result
> 3.5 = 7/2 is an exact binary fraction, unlike 4/10)
If this is indeed about such a set of numbers the obvious solution would
be to scale all values up to integers.
Wouter
== 6 of 10 ==
Date: Thurs, Jan 9 2014 11:11 am
From: Stuart
On 01/09/14, Wouter van Ooijen wrote:
>> This program is effectively calculating something like
>>
>> .4 + .4 + .4 + .4 + .4 + .3 + .3 + .3 + .2 + .4
>>
>> Note that none of these values can be exactly expresses as a float or
>> double so we get numerous round off errors.
>>
>> If instead you computed it as
>>
>> (4.0 + 4.0 + 4.0 + 4.0 + 4.0 + 3.0 + 3.0 + 3.0 + 2.0 + 4.0)/10.0
>>
>> Then each number (having the value of a small integer) can be exactly
>> represented as a double, and the result will be exact (since the result
>> 3.5 = 7/2 is an exact binary fraction, unlike 4/10)
>
> If this is indeed about such a set of numbers the obvious solution would
> be to scale all values up to integers.
IMHO, the obvious solution would be to use a programming language that
takes care of such messy conversions, like Ada95. Ada lets you define
fixed point numbers type so that the actual computation will be done
through integer arithmetic. Ada has a real type system even for
primitive types like int and float, not the C typedef crap. I wish that
this would exist for C++, too, but I'm afraid that such a feature will
never make it into the C++ standard (*sigh*).
Regards,
Stuart
== 7 of 10 ==
Date: Thurs, Jan 9 2014 1:54 pm
From: Wouter van Ooijen
> IMHO, the obvious solution would be to use a programming language that
> takes care of such messy conversions, like Ada95. Ada lets you define
> fixed point numbers type so that the actual computation will be done
> through integer arithmetic. Ada has a real type system even for
> primitive types like int and float, not the C typedef crap. I wish that
> this would exist for C++, too, but I'm afraid that such a feature will
> never make it into the C++ standard (*sigh*).
It doesn't need to, C++ allows you to define such types yourself.
Wouter
== 8 of 10 ==
Date: Thurs, Jan 9 2014 7:51 pm
From: Raymond Li
On 9/1/14 5:46 pm, Raymond Li wrote:
> I have encountered a problem related to floating point rounding. I
> googled a lot and there are many clear and helpful information. e.g.
>
> http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
> http://support.microsoft.com/kb/125056/en-hk
>
>
> Although the urls have explained the cause, I need to find a practical
> way to solve a rounding problem. My program has calculated a weighted
> accumulation as 3.5. When the figure is rounded to nearest number, it
> became 3 (but I want it to round up to 4). I understood it would be due
> to approximation value of 3.5 as 3.49999...
>
> I found a simple fix by using float instead of double. I list the
> program below and wish someone could explain why using double would
> incur the rounding problem while float would not. In the code below,
> fun1() use float and the calculation is 'correct'. In fun2(), it uses
> double and the figure 3.5 is rounded as 3.
>
> Raymond
>
>
>
> //######################
>
>
>
>
> #include <cmath>
> #include <iostream>
>
> //using namespace std;
>
> using std::cout;
> using std::endl;
> int fun1();
> int fun2();
>
> int main(int argc, char ** argv)
> {
> fun1();
> fun2();
> return 0;
> }
>
>
>
> int fun1()
> {
>
> float weighted=10.0;
> float average=100.0;
> float z[]=
> {
> 4.0,
> 4.0,
> 4.0,
> 4.0,
> 4.0,
> 3.0,
> 3.0,
> 3.0,
> 2.0,
> 4.0
> };
>
> float total=0.0;
>
> int i=0;
> for (i=0;i<10;i++)
> {
> float item=z[i]*weighted/average;
> total=total+item;
> cout << i << " accumulate is " << total << endl;
> // NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
> }
>
> float answer=round(total);
> // NSLog(@"rounded is %f", answer);
> cout << "rounded is " << answer << endl;
> return 0;
> }
>
>
> int fun2()
> {
>
> double weighted=10.0;
> double average=100.0;
> double z[]=
> {
> 4.0,
> 4.0,
> 4.0,
> 4.0,
> 4.0,
> 3.0,
> 3.0,
> 3.0,
> 2.0,
> 4.0
> };
>
> double total=0.0;
>
> int i=0;
> for (i=0;i<10;i++)
> {
> double item=z[i]*weighted/average;
> total=total+item;
> cout << i << " accumulate is " << total << endl;
> // NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
> }
>
> double answer=round(total);
> // NSLog(@"rounded is %f", answer);
> cout << "rounded is " << answer << endl;
> return 0;
> }
>
> 0 accumulate is 0.4
> 1 accumulate is 0.8
> 2 accumulate is 1.2
> 3 accumulate is 1.6
> 4 accumulate is 2
> 5 accumulate is 2.3
> 6 accumulate is 2.6
> 7 accumulate is 2.9
> 8 accumulate is 3.1
> 9 accumulate is 3.5
> rounded is 4
> ***(above is the version using float, 3.5 is rounded as 4) ***
>
> 0 accumulate is 0.4
> 1 accumulate is 0.8
> 2 accumulate is 1.2
> 3 accumulate is 1.6
> 4 accumulate is 2
> 5 accumulate is 2.3
> 6 accumulate is 2.6
> 7 accumulate is 2.9
> 8 accumulate is 3.1
> 9 accumulate is 3.5
> rounded is 3
>
> ***(this version use double, 3.5 is rounded as 3) ***
>
>
> --- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Thanks for your replies. I hope to stick to double too. But the users
have implemented the logic in legacy system and I need to convince them
if I do something different from them. They claimed that the interim
calculations (z[i]*weighted/average) are used too and they would feel
uncomfortable if I make any adjustment. The worst problem I faced is
that they claimed that the legacy system (which is not really legacy, it
is running Oracle pl/sql) does not have the rounding error.
So I investigated and found it weird that the rounding problem could be
avoided by using float. I am uncomfortable to this workaround (using
float), as I am afraid there would be cases that the rounding issue
recur in other scenarios. So I really want someone could explain why the
float datatype would round correctly in the above case, while using
double rounded 'incorrectly'.
If I am free to rewrite the code, after learning from you, I would
rewrite the code as follow. The problem is that I have to convince my
users, and their legacy system was already implemented.
Regards,
Raymond
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <iomanip>
using std::setprecision;
using std::cout;
using std::endl;
int fun3();
int main(int argc, const char * argv[])
{
// insert code here...
// std::cout << "Hello, World!\n";
fun3();
return 0;
}
int fun3()
{
cout << setprecision(17);
double weighted=10.0;
double average=100.0;
double z[]=
{
4.0,
4.0,
4.0,
4.0,
4.0,
3.0,
3.0,
3.0,
2.0,
4.0
};
double total=0.0;
int i=0;
for (i=0;i<10;i++)
{
//double item=z[i]*weighted/average;
double item=z[i]*weighted; // defer the division
total=total+item;
cout << "in loop " << i << ", accumulate is " << total << endl;
// NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
}
total=total/average; // division done at last to avoid truncation error
double answer=round(total);
cout << "rounded is " << answer << " and original is " << total <<
endl;
return 0;
}
output:
in loop 0, accumulate is 40
in loop 1, accumulate is 80
in loop 2, accumulate is 120
in loop 3, accumulate is 160
in loop 4, accumulate is 200
in loop 5, accumulate is 230
in loop 6, accumulate is 260
in loop 7, accumulate is 290
in loop 8, accumulate is 310
in loop 9, accumulate is 350
rounded is 4 and original is 3.5
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
== 9 of 10 ==
Date: Thurs, Jan 9 2014 8:39 pm
From: Richard Damon
On 1/9/14, 10:51 PM, Raymond Li wrote:
> Thanks for your replies. I hope to stick to double too. But the users
> have implemented the logic in legacy system and I need to convince them
> if I do something different from them. They claimed that the interim
> calculations (z[i]*weighted/average) are used too and they would feel
> uncomfortable if I make any adjustment. The worst problem I faced is
> that they claimed that the legacy system (which is not really legacy, it
> is running Oracle pl/sql) does not have the rounding error.
>
> So I investigated and found it weird that the rounding problem could be
> avoided by using float. I am uncomfortable to this workaround (using
> float), as I am afraid there would be cases that the rounding issue
> recur in other scenarios. So I really want someone could explain why the
> float datatype would round correctly in the above case, while using
> double rounded 'incorrectly'.
>
> If I am free to rewrite the code, after learning from you, I would
> rewrite the code as follow. The problem is that I have to convince my
> users, and their legacy system was already implemented.
>
> Regards,
> Raymond
>
Float eliminates the error IN THIS EXAMPLE, not in general, it probably
is a matter of which round down and which round up after the divide by
100.0. There will be other example number sets where double is right but
float is wrong.
Unless you run a lot of tests with a number of different cases, which
similarly stress the accuracy, it would be impossible to say "does not
have the rounding problem", it just shows that it doesn't have it for
THAT set of numbers. The one case where I would believe it really not
having a rounding problem would be a system that did the math in
decimal, instead of binary, those systems, while the do have round off
errors, have them where decimal thinking people expect them, so they
don't complain.
A question on operation, in "real" use, are the numbers going to be this
nice? If they are, then you may be able to adjust the rounding so that
0.499 rounds up instead of down. If they aren't then you are going run
into the fact that this is a pathological one in a million case of the
sum just hitting the break point of the round function, and the round
off error makes you cross over the line.
== 10 of 10 ==
Date: Thurs, Jan 9 2014 9:39 pm
From: Robert Wessel
On Fri, 10 Jan 2014 11:51:54 +0800, Raymond Li <faihk1@gmail.com>
wrote:
>On 9/1/14 5:46 pm, Raymond Li wrote:
>> I have encountered a problem related to floating point rounding. I
>> googled a lot and there are many clear and helpful information. e.g.
>>
>> http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
>> http://support.microsoft.com/kb/125056/en-hk
>>
>>
>> Although the urls have explained the cause, I need to find a practical
>> way to solve a rounding problem. My program has calculated a weighted
>> accumulation as 3.5. When the figure is rounded to nearest number, it
>> became 3 (but I want it to round up to 4). I understood it would be due
>> to approximation value of 3.5 as 3.49999...
>>
>> I found a simple fix by using float instead of double. I list the
>> program below and wish someone could explain why using double would
>> incur the rounding problem while float would not. In the code below,
>> fun1() use float and the calculation is 'correct'. In fun2(), it uses
>> double and the figure 3.5 is rounded as 3.
>>
>> Raymond
>>
>>
>>
>> //######################
>>
>>
>>
>>
>> #include <cmath>
>> #include <iostream>
>>
>> //using namespace std;
>>
>> using std::cout;
>> using std::endl;
>> int fun1();
>> int fun2();
>>
>> int main(int argc, char ** argv)
>> {
>> fun1();
>> fun2();
>> return 0;
>> }
>>
>>
>>
>> int fun1()
>> {
>>
>> float weighted=10.0;
>> float average=100.0;
>> float z[]=
>> {
>> 4.0,
>> 4.0,
>> 4.0,
>> 4.0,
>> 4.0,
>> 3.0,
>> 3.0,
>> 3.0,
>> 2.0,
>> 4.0
>> };
>>
>> float total=0.0;
>>
>> int i=0;
>> for (i=0;i<10;i++)
>> {
>> float item=z[i]*weighted/average;
>> total=total+item;
>> cout << i << " accumulate is " << total << endl;
>> // NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
>> }
>>
>> float answer=round(total);
>> // NSLog(@"rounded is %f", answer);
>> cout << "rounded is " << answer << endl;
>> return 0;
>> }
>>
>>
>> int fun2()
>> {
>>
>> double weighted=10.0;
>> double average=100.0;
>> double z[]=
>> {
>> 4.0,
>> 4.0,
>> 4.0,
>> 4.0,
>> 4.0,
>> 3.0,
>> 3.0,
>> 3.0,
>> 2.0,
>> 4.0
>> };
>>
>> double total=0.0;
>>
>> int i=0;
>> for (i=0;i<10;i++)
>> {
>> double item=z[i]*weighted/average;
>> total=total+item;
>> cout << i << " accumulate is " << total << endl;
>> // NSLog(@"z[%d] is %f, total is %f", i, z[i], total);
>> }
>>
>> double answer=round(total);
>> // NSLog(@"rounded is %f", answer);
>> cout << "rounded is " << answer << endl;
>> return 0;
>> }
>>
>> 0 accumulate is 0.4
>> 1 accumulate is 0.8
>> 2 accumulate is 1.2
>> 3 accumulate is 1.6
>> 4 accumulate is 2
>> 5 accumulate is 2.3
>> 6 accumulate is 2.6
>> 7 accumulate is 2.9
>> 8 accumulate is 3.1
>> 9 accumulate is 3.5
>> rounded is 4
>> ***(above is the version using float, 3.5 is rounded as 4) ***
>>
>> 0 accumulate is 0.4
>> 1 accumulate is 0.8
>> 2 accumulate is 1.2
>> 3 accumulate is 1.6
>> 4 accumulate is 2
>> 5 accumulate is 2.3
>> 6 accumulate is 2.6
>> 7 accumulate is 2.9
>> 8 accumulate is 3.1
>> 9 accumulate is 3.5
>> rounded is 3
>>
>> ***(this version use double, 3.5 is rounded as 3) ***
>>
>>
>> --- news://freenews.netfront.net/ - complaints: news@netfront.net ---
>
>Thanks for your replies. I hope to stick to double too. But the users
>have implemented the logic in legacy system and I need to convince them
>if I do something different from them. They claimed that the interim
>calculations (z[i]*weighted/average) are used too and they would feel
>uncomfortable if I make any adjustment. The worst problem I faced is
>that they claimed that the legacy system (which is not really legacy, it
>is running Oracle pl/sql) does not have the rounding error.
>
>So I investigated and found it weird that the rounding problem could be
>avoided by using float. I am uncomfortable to this workaround (using
>float), as I am afraid there would be cases that the rounding issue
>recur in other scenarios. So I really want someone could explain why the
>float datatype would round correctly in the above case, while using
>double rounded 'incorrectly'.
You shouldn't depend on that, it's just a coincidence of how the
rounding error happened to accumulate.
I've modified you program to display a bit more precision (attached
below). With the better display of precision, you can see the
roundoff errors accumulating differently:
(float) 0 item is 0.40000000596046448 accumulate is
0.40000000596046448
(float) 1 item is 0.40000000596046448 accumulate is
0.80000001192092896
(float) 2 item is 0.40000000596046448 accumulate is 1.2000000476837158
(float) 3 item is 0.40000000596046448 accumulate is 1.6000000238418579
(float) 4 item is 0.40000000596046448 accumulate is 2
(float) 5 item is 0.30000001192092896 accumulate is 2.2999999523162842
(float) 6 item is 0.30000001192092896 accumulate is 2.5999999046325684
(float) 7 item is 0.30000001192092896 accumulate is 2.8999998569488525
(float) 8 item is 0.20000000298023224 accumulate is 3.0999999046325684
(float) 9 item is 0.40000000596046448 accumulate is 3.5
rounded is 4
(double) 0 item is 0.40000000000000002 accumulate is
0.40000000000000002
(double) 1 item is 0.40000000000000002 accumulate is
0.80000000000000004
(double) 2 item is 0.40000000000000002 accumulate is
1.2000000000000002
(double) 3 item is 0.40000000000000002 accumulate is
1.6000000000000001
(double) 4 item is 0.40000000000000002 accumulate is 2
(double) 5 item is 0.29999999999999999 accumulate is
2.2999999999999998
(double) 6 item is 0.29999999999999999 accumulate is
2.5999999999999996
(double) 7 item is 0.29999999999999999 accumulate is
2.8999999999999995
(double) 8 item is 0.20000000000000001 accumulate is
3.0999999999999996
(double) 9 item is 0.40000000000000002 accumulate is
3.4999999999999996
rounded is 3
But as I said, you can depend on that. For example, changing the
series to:
{
9.0,
9.0,
9.0,
8.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
Will cause the float version to round to 3 as well:
(float) 0 item is 0.89999997615814209 accumulate is
0.89999997615814209
(float) 1 item is 0.89999997615814209 accumulate is 1.7999999523162842
(float) 2 item is 0.89999997615814209 accumulate is 2.6999998092651367
(float) 3 item is 0.80000001192092896 accumulate is 3.4999997615814209
(float) 4 item is 0 accumulate is 3.4999997615814209
(float) 5 item is 0 accumulate is 3.4999997615814209
(float) 6 item is 0 accumulate is 3.4999997615814209
(float) 7 item is 0 accumulate is 3.4999997615814209
(float) 8 item is 0 accumulate is 3.4999997615814209
(float) 9 item is 0 accumulate is 3.4999997615814209
rounded is 3
IOW, this will vary with the exact set of inputs. So don't do that.
Even worse, you can get this to wander around based on whether or not
you tell the compiler to produce strict IEEE compliant math, and the
requested optimization level (on x86 machines you often see
intermediate results with a higher precision than you'd expect if the
code is using the x87 FPU).
Changing the values (as has been suggested) so that all of them have
exact representations can reduce the roundoff error, but cannot
eliminate it (you'll still get roundoff error on that final division,
even if you get none on the individual terms). OTOH, you probably
will get away with this so long as the only case you care about is
"xxx5.0 / 10.0", since that will have an exact result (.5 being
exactly representable in a binary FP number). This is obviously
fragile, and will go to pot the first time someone tosses in a number
with more than a single decimal place.
If this is important, I'd generally advise avoiding floating point
entirely, and use a package that allows you to do this all with scaled
integers or rationals. I'm not sure what the PL/SQL code is doing,
but it may be using a scaled type, or if it's using a floating type,
they might just be hitting one set of rounding errors that happens to
generate the expected result. And that may just be the worst scenario
- trying to duplicate the existing behavior when the existing behavior
is not what anyone is actually expecting.
/* ----- */
#include <cmath>
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
int fun1();
int fun2();
inline int round(double x) { return (floor(x + 0.5)); }
int main(int argc, char ** argv)
{
fun1();
fun2();
return 0;
}
int fun1()
{
float weighted=10.0;
float average=100.0;
float z[]=
{
4.0,
4.0,
4.0,
4.0,
4.0,
3.0,
3.0,
3.0,
2.0,
4.0
};
float total=0.0;
int i=0;
for (i=0;i<10;i++)
{
float item=z[i]*weighted/average;
total=total+item;
cout << "(float) " << i << " item is " <<
std::setprecision(20) << item
<< " accumulate is " << std::setprecision(20) << total
<< endl;
}
float answer=round(total);
cout << "rounded is " << answer << endl;
return 0;
}
int fun2()
{
double weighted=10.0;
double average=100.0;
double z[]=
{
4.0,
4.0,
4.0,
4.0,
4.0,
3.0,
3.0,
3.0,
2.0,
4.0
};
double total=0.0;
int i=0;
for (i=0;i<10;i++)
{
double item=z[i]*weighted/average;
total=total+item;
cout << "(double) " << i << " item is " <<
std::setprecision(20) << item
<< " accumulate is " << std::setprecision(20) << total
<< endl;
}
double answer=round(total);
cout << "rounded is " << answer << endl;
return 0;
}
==============================================================================
TOPIC: Friendly GUI for windows building?
http://groups.google.com/group/comp.lang.c++/t/c865fa27ccf9e327?hl=en
==============================================================================
== 1 of 1 ==
Date: Fri, Jan 10 2014 12:08 am
From: Francois Guillet
Rupert Miscavige a pr�sent� l'�nonc� suivant :
...
> Sure it is. Crap. The proof for this is that they are unable to compile a
> windows binary, for whatever reasons, then let the user using it.
> Directly, as they are supposed to do.
And what do you suggest instead which would be better ?
==============================================================================
You received this message because you are subscribed to the Google Groups "comp.lang.c++"
group.
To post to this group, visit http://groups.google.com/group/comp.lang.c++?hl=en
To unsubscribe from this group, send email to comp.lang.c+++unsubscribe@googlegroups.com
To change the way you get mail from this group, visit:
http://groups.google.com/group/comp.lang.c++/subscribe?hl=en
To report abuse, send email explaining the problem to abuse@googlegroups.com
==============================================================================
Google Groups: http://groups.google.com/?hl=en
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment