PC Review


Reply
Thread Tools Rate Thread

Bug with the function Round !

 
 
Tschuß
Guest
Posts: n/a
 
      18th Mar 2010
Hi all,

I was making an exercise for my students when I have discovered a bug
when I use the function Round.
In the column E, you have this data
Last quote
32,13
31,46
31,67
31,17
30,12
31,86
31,96
33,28
33,35
33,38
33,08
33,34
32,38
31,98
32,09
32,73
33,05
32,82
33,08

My program is very simple. I calculate the average of the first 20
cells and I write the result in Cells(21,6)
Why the round function doesn't work in the first Sub (the result is
32,4099998474121) and works in the second one ?
Thanks for any idea.

Sub Step_1()
Dim Temp_Sum As Single
Dim index_loop As Integer

For index_loop = 1 To 20
Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
Next
Cells(21, 6) = Round(Temp_Sum / 20, 2)

End Sub

(the cell(1,6) has the value 20)
Sub Step_2()
Dim Temp_Sum As Single
Dim index_loop As Integer

For index_loop = 1 To Cells(1, 6)
Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
Next
Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)

End Sub


 
Reply With Quote
 
 
 
 
Monarch
Guest
Posts: n/a
 
      18th Mar 2010
Cells(1,6) is Variant/Double
20 is integer
Temp_Sum is single...

if you try Cells(22, 6) = Round(Temp_Sum / 20#, 2)
it will work

On 18.03.2010 16:52, Tschuß wrote:
> Hi all,
>
> I was making an exercise for my students when I have discovered a bug
> when I use the function Round.
> In the column E, you have this data
> Last quote
> 32,13
> 31,46
> 31,67
> 31,17
> 30,12
> 31,86
> 31,96
> 33,28
> 33,35
> 33,38
> 33,08
> 33,34
> 32,38
> 31,98
> 32,09
> 32,73
> 33,05
> 32,82
> 33,08
>
> My program is very simple. I calculate the average of the first 20
> cells and I write the result in Cells(21,6)
> Why the round function doesn't work in the first Sub (the result is
> 32,4099998474121) and works in the second one ?
> Thanks for any idea.
>
> Sub Step_1()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To 20
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
> End Sub
>
> (the cell(1,6) has the value 20)
> Sub Step_2()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To Cells(1, 6)
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
> End Sub
>
>

 
Reply With Quote
 
Monarch
Guest
Posts: n/a
 
      18th Mar 2010
Also
this does not round
Cells(22, 6) = Round(CSng(Temp_Sum / 20), 2)
but this does it
Cells(22, 6) = Round(CDbl(Temp_Sum / 20), 2)

so explanation is that single data does not have enough precision

On 18.03.2010 17:44, Monarch wrote:
> Cells(1,6) is Variant/Double
> 20 is integer
> Temp_Sum is single...
>
> if you try Cells(22, 6) = Round(Temp_Sum / 20#, 2)
> it will work
>
> On 18.03.2010 16:52, Tschuß wrote:
>> Hi all,
>>
>> I was making an exercise for my students when I have discovered a bug
>> when I use the function Round.
>> In the column E, you have this data
>> Last quote
>> 32,13
>> 31,46
>> 31,67
>> 31,17
>> 30,12
>> 31,86
>> 31,96
>> 33,28
>> 33,35
>> 33,38
>> 33,08
>> 33,34
>> 32,38
>> 31,98
>> 32,09
>> 32,73
>> 33,05
>> 32,82
>> 33,08
>>
>> My program is very simple. I calculate the average of the first 20
>> cells and I write the result in Cells(21,6)
>> Why the round function doesn't work in the first Sub (the result is
>> 32,4099998474121) and works in the second one ?
>> Thanks for any idea.
>>
>> Sub Step_1()
>> Dim Temp_Sum As Single
>> Dim index_loop As Integer
>>
>> For index_loop = 1 To 20
>> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
>> Next
>> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>>
>> End Sub
>>
>> (the cell(1,6) has the value 20)
>> Sub Step_2()
>> Dim Temp_Sum As Single
>> Dim index_loop As Integer
>>
>> For index_loop = 1 To Cells(1, 6)
>> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
>> Next
>> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>>
>> End Sub
>>
>>

 
Reply With Quote
 
Gary''s Student
Guest
Posts: n/a
 
      18th Mar 2010
You only list 19 values in your post. Do you want the 20th value to be zero
or blank??
--
Gary''s Student - gsnu201001


"Tschuß" wrote:

> Hi all,
>
> I was making an exercise for my students when I have discovered a bug
> when I use the function Round.
> In the column E, you have this data
> Last quote
> 32,13
> 31,46
> 31,67
> 31,17
> 30,12
> 31,86
> 31,96
> 33,28
> 33,35
> 33,38
> 33,08
> 33,34
> 32,38
> 31,98
> 32,09
> 32,73
> 33,05
> 32,82
> 33,08
>
> My program is very simple. I calculate the average of the first 20
> cells and I write the result in Cells(21,6)
> Why the round function doesn't work in the first Sub (the result is
> 32,4099998474121) and works in the second one ?
> Thanks for any idea.
>
> Sub Step_1()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To 20
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
> End Sub
>
> (the cell(1,6) has the value 20)
> Sub Step_2()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To Cells(1, 6)
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
> End Sub
>
>
> .
>

 
Reply With Quote
 
Ron Rosenfeld
Guest
Posts: n/a
 
      18th Mar 2010
On Thu, 18 Mar 2010 08:52:03 -0700 (PDT), Tschuß <(E-Mail Removed)> wrote:

>Hi all,
>
>I was making an exercise for my students when I have discovered a bug
>when I use the function Round.
>In the column E, you have this data
>Last quote
>32,13
>31,46
>31,67
>31,17
>30,12
>31,86
>31,96
>33,28
>33,35
>33,38
>33,08
>33,34
>32,38
>31,98
>32,09
>32,73
>33,05
>32,82
>33,08
>
>My program is very simple. I calculate the average of the first 20
>cells and I write the result in Cells(21,6)
>Why the round function doesn't work in the first Sub (the result is
>32,4099998474121) and works in the second one ?
>Thanks for any idea.
>
>Sub Step_1()
>Dim Temp_Sum As Single
>Dim index_loop As Integer
>
> For index_loop = 1 To 20
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
>End Sub
>
>(the cell(1,6) has the value 20)
>Sub Step_2()
>Dim Temp_Sum As Single
>Dim index_loop As Integer
>
> For index_loop = 1 To Cells(1, 6)
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
>End Sub
>


Your first Sub seems to work properly, returning 32.40999984741210
provided that you put a 33.27 into E21 (the 20th cell in the series). As
written above, you only have 19 values.
--ron
 
Reply With Quote
 
Skiffle
Guest
Posts: n/a
 
      19th Mar 2010
"Tschuß",

As Monarch pointed out, a variable dimensioned as Single does not have the
necessary precision for the task at hand.

In general, it is rarely necessary to dimension any variable as Single or
Integer. Those variables would better be served as Double or Long,
respectively.

Single or Integer variables were used more frequently when conservation of
memory was a concern. Single or Integer variables require less internal
memory than their Double or Long counterparts. Since memory is so
inexpensive today and usually in abundance, conserving it is no longer
considered necessary. Therefore, Double or Long is more common practice in
place of Single or Integer.


"Tschuß" <(E-Mail Removed)> wrote in message
news:128ec55a-505e-4390-b697-(E-Mail Removed)...
> Hi all,
>
> I was making an exercise for my students when I have discovered a bug
> when I use the function Round.
> In the column E, you have this data
> Last quote
> 32,13
> 31,46
> 31,67
> 31,17
> 30,12
> 31,86
> 31,96
> 33,28
> 33,35
> 33,38
> 33,08
> 33,34
> 32,38
> 31,98
> 32,09
> 32,73
> 33,05
> 32,82
> 33,08
>
> My program is very simple. I calculate the average of the first 20
> cells and I write the result in Cells(21,6)
> Why the round function doesn't work in the first Sub (the result is
> 32,4099998474121) and works in the second one ?
> Thanks for any idea.
>
> Sub Step_1()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To 20
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
> End Sub
>
> (the cell(1,6) has the value 20)
> Sub Step_2()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To Cells(1, 6)
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
> End Sub
>
>


 
Reply With Quote
 
Joe User
Guest
Posts: n/a
 
      19th Mar 2010
"Tschuß" <(E-Mail Removed)> wrote:
> Why the round function doesn't work in the first
> Sub (the result is 32,4099998474121) and works in
> the second one ?


Your explanation is incomplete (what does "work" mean?); but so are the
responses posted so far, IMHO. Let me fill in the blanks. (Note: I use
period instead of comma as the radix point.)

First, it appears that your question is: why does the first macro result in
32.4099998474121, whereas the second macro results in 32.4100000000000 as
you expect?

Your observation is correct, assuming that the missing 20th data value is
33.27.

As others have noted, the root cause of the problem is your use of Single
instead of Double. The problem arises when your Single expression is
converted to Double, the precision used for numbers in Excel cells.

In the statement `Cells(21, 6) = Round(Temp_Sum / 20, 2)` in the Step_1
macro, the result of Round() has Single precision because Temp_Sum is type
Single and 20 is an integer. The Single precision right-hand side is then
converted to Double, conceptually by appending zero bits on the right. This
is an imperfect conversion, as I will demonstrate below.

(Note: A Single value is represented using 32-bit floating point, whereas a
Double is represented using 64-bit floating point.)

In contrast, in the statement `Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum /
Cells(1, 6), 2)` n the Step_2 macro, the result of Round() has Double
precision because Temp_Sum is converted to Double since Cells(1,6) has
Double precision. Although the Temp_Sum conversion is also imperfect, the
Round() precision of 2 is sufficiently small to mask the imperfect result of
Temp_Sum / Cells(1, 6).

In order to understand the imperfect conversion of Single to Double, it is
necessary to look at the binary representation of numbers. Most numbers
with fractional digits cannot be represented exactly because the floating
point representation is the sum of a finite number of consecutive powers of
2 -- 53 for Double, 24 for Single.

Consequently, the Double value 32.41 is represented by &h4040347A,E147AE14.
But when the Single value 32.41 is converted to Double, it is represented by
&h4040347A,E0000000.

Obviously, these are two different representations, representing two
different numbers.

In summary, the problem is not with Round(), but with the necessarily
imperfect hardware conversion of Single to Double.

You could avoid the imperfect conversion by first converting the Single
expression to text. For example, Format(Round(Temp_Sum / 20, 2), "0.00")
or, more simply, Format(Temp_Sum / 20, "0.00").

Of course, the better solution is simply to use type Double instead of
Single.

There is little benefit to using Single these days. Single does require
less memory; but that should be significant only when you are dealing huge
amounts of data, e.g. billions of data values. In most modern computers,
there is no performance benefit to using Single.

It should be noted that in both macros, the statement `Temp_Sum = Temp_Sum +
Cells(1 + index_loop, 5)` repeatedly causes infinitesimal imperfections in
the computation when the Double expression on the right-hand side is rounded
to Single precision for assignment to the left-hand side.

All the more reason to use type Double instead of Single consistently.


----- original message -----

"Tschuß" <(E-Mail Removed)> wrote in message
news:128ec55a-505e-4390-b697-(E-Mail Removed)...
> Hi all,
>
> I was making an exercise for my students when I have discovered a bug
> when I use the function Round.
> In the column E, you have this data
> Last quote
> 32,13
> 31,46
> 31,67
> 31,17
> 30,12
> 31,86
> 31,96
> 33,28
> 33,35
> 33,38
> 33,08
> 33,34
> 32,38
> 31,98
> 32,09
> 32,73
> 33,05
> 32,82
> 33,08
>
> My program is very simple. I calculate the average of the first 20
> cells and I write the result in Cells(21,6)
> Why the round function doesn't work in the first Sub (the result is
> 32,4099998474121) and works in the second one ?
> Thanks for any idea.
>
> Sub Step_1()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To 20
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
> End Sub
>
> (the cell(1,6) has the value 20)
> Sub Step_2()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> For index_loop = 1 To Cells(1, 6)
> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> Next
> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
> End Sub
>
>


 
Reply With Quote
 
Tschuß
Guest
Posts: n/a
 
      19th Mar 2010

Thanks all for your answer.

First, I apology because it's true that I forgot the last value ;
33.21
@Monarch : Could you explain me the contribution of the symbol # after
20 ?
@Joe User : Thanks a lot for your explanation (expect for the
hexadecimal part). But I understand that it's better to use Double in
any case.




On 18 mar, 16:52, Tschuß <fleg...@gmail.com> wrote:
> Hi all,
>
> I was making an exercise for my students when I have discovered a bug
> when I use the function Round.
> In the column E, you have this data
> Last quote
> 32,13
> 31,46
> 31,67
> 31,17
> 30,12
> 31,86
> 31,96
> 33,28
> 33,35
> 33,38
> 33,08
> 33,34
> 32,38
> 31,98
> 32,09
> 32,73
> 33,05
> 32,82
> 33,08
>
> My program is very simple. I calculate the average of the first 20
> cells and I write the result in Cells(21,6)
> Why the round function doesn't work in the first Sub (the result is
> 32,4099998474121) and works in the second one ?
> Thanks for any idea.
>
> Sub Step_1()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> * * For index_loop = 1 To 20
> * * * * Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> * * Next
> * * Cells(21, 6) = Round(Temp_Sum / 20, 2)
>
> End Sub
>
> (the cell(1,6) has the value 20)
> Sub Step_2()
> Dim Temp_Sum As Single
> Dim index_loop As Integer
>
> * * For index_loop = 1 To Cells(1, 6)
> * * * * Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
> * * Next
> * * Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>
> End Sub


 
Reply With Quote
 
Monarch
Guest
Posts: n/a
 
      19th Mar 2010
Sign Language ..
Type Declaration chararcters...
% - integer
& - Long
# - Double
! - single
@ - Currency

short way to convert values...
20! is single, 20# is double, 20 or 20% is integer

run this macro

Sub test()
aInt = TypeName(20)
aDbl = TypeName(20#)
aSng = TypeName(20!)
aCur = TypeName(20@)
aLng = TypeName(20&)
MsgBox aInt & " " & aDbl & " " & aSng & " " & aCur & " " & aLng
End Sub



On 19.03.2010 07:35, Tschuß wrote:
>
> Thanks all for your answer.
>
> First, I apology because it's true that I forgot the last value ;
> 33.21
> @Monarch : Could you explain me the contribution of the symbol # after
> 20 ?
> @Joe User : Thanks a lot for your explanation (expect for the
> hexadecimal part). But I understand that it's better to use Double in
> any case.
>
>
>
>
> On 18 mar, 16:52, Tschuß<fleg...@gmail.com> wrote:
>> Hi all,
>>
>> I was making an exercise for my students when I have discovered a bug
>> when I use the function Round.
>> In the column E, you have this data
>> Last quote
>> 32,13
>> 31,46
>> 31,67
>> 31,17
>> 30,12
>> 31,86
>> 31,96
>> 33,28
>> 33,35
>> 33,38
>> 33,08
>> 33,34
>> 32,38
>> 31,98
>> 32,09
>> 32,73
>> 33,05
>> 32,82
>> 33,08
>>
>> My program is very simple. I calculate the average of the first 20
>> cells and I write the result in Cells(21,6)
>> Why the round function doesn't work in the first Sub (the result is
>> 32,4099998474121) and works in the second one ?
>> Thanks for any idea.
>>
>> Sub Step_1()
>> Dim Temp_Sum As Single
>> Dim index_loop As Integer
>>
>> For index_loop = 1 To 20
>> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
>> Next
>> Cells(21, 6) = Round(Temp_Sum / 20, 2)
>>
>> End Sub
>>
>> (the cell(1,6) has the value 20)
>> Sub Step_2()
>> Dim Temp_Sum As Single
>> Dim index_loop As Integer
>>
>> For index_loop = 1 To Cells(1, 6)
>> Temp_Sum = Temp_Sum + Cells(1 + index_loop, 5)
>> Next
>> Cells(1 + Cells(1, 6), 6) = Round(Temp_Sum / Cells(1, 6), 2)
>>
>> End Sub

>

 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
VB Function Round vs Excel function Round not behaving the same Od =?Utf-8?B?QnVk?= Microsoft Excel Programming 5 18th Aug 2006 05:39 AM
can you nested sum and round function within if function? =?Utf-8?B?YW5uYQ==?= Microsoft Excel Worksheet Functions 4 27th May 2006 06:06 AM
Trying to do a round function but unable to get it to function =?Utf-8?B?TmVlZGhlbHBpblRlbm5lc3NlZQ==?= Microsoft Excel Worksheet Functions 11 30th Sep 2004 01:18 AM
Round function Emmy Microsoft Access Queries 3 30th Jun 2004 03:30 PM
Round function - round to 5 freimc Microsoft Excel Worksheet Functions 3 18th May 2004 11:36 AM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 10:08 AM.