Try the follow code in IE and you'll see:
var a = 0.94
alert(a.toFixed())
Or the following for WSH
var a = 0.94
WScript.Echo(a.toFixed())
Per the JScript documentation:
Arguments
numObj
Required A Number object.
fractionDigits
Optional. Number of digits after the decimal point. Must be in the range
0 - 20, inclusive.
Remarks
The toFixed method returns a string representation of a number in
fixed-point notation. The string contains one digit before the significand's
decimal point, and must contain fractionDigits digits after it.
If fractionDigits is not supplied or undefined, the toFixed method assumes
the value is zero.
Thus, 0.94 to zero digits after the decimal (i.e. "0").
var a = 0.94;
WScript.Echo(a.toFixed()); // "0"
WScript.Echo(a.toFixed( 1 )); // "0.9"
WScript.Echo(a.toFixed( 2 )); // "0.94"
WScript.Echo(a.toFixed( 3 )); // "0.940"
Dale Hurtt
Consider:
(0.94).toFixed() returns "0"
(0.95).toFixed() returns "1"
(1.94).toFixed() returns "2"
Similar results with negative numbers:
(-0.94).toFixed() returns "0"
(-0.95).toFixed() returns "-1"
"Dale Hurtt" wrote:
>
> If fractionDigits is not supplied or undefined, the toFixed method assumes
> the value is zero.
>
> Thus, 0.94 to zero digits after the decimal (i.e. "0").
>
> var a = 0.94;
> WScript.Echo(a.toFixed()); // "0"
> WScript.Echo(a.toFixed( 1 )); // "0.9"
> WScript.Echo(a.toFixed( 2 )); // "0.94"
> WScript.Echo(a.toFixed( 3 )); // "0.940"
--
Dave Anderson
Unsolicited commercial email will be read at a cost of $500 per message. Use of
this email address implies consent to these terms. Please do not contact me
directly or ask me to contact you directly for assistance. If your question is
worth asking, it's worth posting.
Then explain the third string produced by:
var a = 0.906;
WScript.Echo(a.toFixed(0), a.toFixed(1), a.toFixed(2), a.toFixed(3));
If toFixed truncates, the string should be "0.90". If toFixed rounds, the first
string should be "1". Either way, JScript's implementation of toFixed returns
inconsistent results (i.e. is buggy).
--
Steve
Speech is conveniently located midway between thought and action, where it
often substitutes for both. -John Andrew Holmes
Why would you think that? Both the JScript documentation and the ECMAScript
standards indicate that no rounding as you suggest occurs. The method
Number.toFixed ( ) (from the standard 15.7.4.5):
"Returns a string containing the number represented in fixed-point notation
with fractionDigits digits after the decimal point. If fractionDigits is
undefined, 0 is assumed."
The integer portion of 0.94 is "0" (see the standard above, step 11). The
fractional part is "94", but with zero digits showing it translates to "". 0
+ "" is "0".
Perhaps Math.ceil ( 0.94) will return the value he wants... But, toFixed
does not appear to have a "bug".
Dale Hurtt
And I'm glad you brought up ECMA, because we can step through the ECMA
specification with (0.94).toFixed():
: Number.prototype.toFixed (fractionDigits)
: Return a string containing the number represented in fixed-point
: notation with fractionDigits digits after the decimal point. If
: fractionDigits is undefined, 0 is assumed. Specifically, perform
: the following steps:
:
: 1. Let f be ToInteger(fractionDigits). (If fractionDigits is
: undefined, this step produces the value 0).
f = 0
: 2. If f < 0 or f > 20, throw a RangeError exception.
: 3. Let x be this number value.
x = 0.94
: 4. If x is NaN, return the string "NaN".
: 5. Let s be the empty string.
s = ""
: 6. If x >= 0, go to step 9.
Skipping to step 9...
: 7. Let s be "-".
: 8. Let x = -x.
: 9. If x >= 10^21, let m = ToString(x) and go to step 20.
0.94 < 10^21, so continue...
: 10. Let n be an integer for which the exact mathematical value of
: n/10^f - x is as close to zero as possible. If there are two
: such n, pick the larger n.
n/10^0 = n/1 = n, which must be the closest integer to 0.94. This is the
rounding step. Since f is 0, this says "pick the closest integer to x, rounding
up". Thus, n = 1.
: 11. If n = 0, let m be the string "0". Otherwise, let m be the
: string consisting of the digits of the decimal representation
: of n (in order, with no leading zeroes).
m = "1"
: 12. If f = 0, go to step 20.
f = 0, so let's go to step 20...
: 13. Let k be the number of characters in m.
: 14. If k > f, go to step 18.
: 15. Let z be the string consisting of f+1-k occurrences of the
: character "0".
: 16. Let m be the concatenation of strings z and m.
: 17. Let k = f + 1.
: 18. Let a be the first k每f characters of m, and let b be the
: remaining f characters of m.
: 19. Let m be the concatenation of the three strings a, ".",
: and b.
: 20. Return the concatenation of the strings s and m.
return value: ("" + "1")
Thus, JScript does not conform to the ECMA 262 spec for Number.toFixed(). Could
not be more evident.
"Dale Hurtt" wrote:
>
> Why would you think that? Both the JScript documentation and the ECMAScript
> standards indicate that no rounding as you suggest occurs. The method
> Number.toFixed ( ) (from the standard 15.7.4.5):
>
> "Returns a string containing the number represented in fixed-point notation
> with fractionDigits digits after the decimal point. If fractionDigits is
> undefined, 0 is assumed."
>
> The integer portion of 0.94 is "0" (see the standard above, step 11). The
> fractional part is "94", but with zero digits showing it translates to "". 0
> + "" is "0".
This is where you read the spec incorrectly. Step 11 does not look at the
integer portion of x, it looks at the computed value n, which is 1.
> Perhaps Math.ceil (0.94) will return the value he wants...
> But, toFixed does not appear to have a "bug".
On the contrary, it has a demonstrated and illustrated bug.
I stand corrected. I misread the formula as "n/10^f - x" (I saw the em dash
in my PDF as a minus). [snort] When I did the math using the steps, using
the incorrect formula, the integer would always have to be zero. Kind of
skews the results, huh.
My bust.
Dale Hurtt
See <URL:http://www.merlyn.demon.co.uk/js-round.htm#RoundS> para 2.
--
© John Stockton, Surrey, UK. j...@merlyn.demon.co.uk Turnpike v4.00 MSIE 4 ©
<URL:http://www.jibbering.com/faq/> FAQ for comp.lang.javascript by Jim Ley.
<URL:http://www.merlyn.demon.co.uk/js-index.htm> JS maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/JS/&c., FAQ topics, links.
I have to say sorry because my mail was too short and
unclear. Yes, the problem is that values between 0.5 and
0.94 aren't rounded to 1 using toFixed. Consider this :
Example 1 :
(0.94).toFixed(0) gives 0 whilst
(0.95).toFixed(0) gives 1 !!
Example 2 :
(0.88).toFixed(0) gives 0 whilst
(1.88).toFixed(0) gives 2 !!
I think now everybody agrees that toFixed is buggy, and
now the most important question is :
What could we do to make Microsoft aware of this problem?
This problem is quite serious because it affects
everything using JScript engine, from IE to ASP through
WSH. My computer is making a kind of accounting Web
application and this bug is very very annoying. I just
couldn't tell my clients that IE is buggy and there's
nothing I could do. Nobody would be happy about this. If
the solution isn't available in the following months, I
think I'm forced to tell my clients to use Netscape 7
because, sorry to Microsoft supporters and fans, I find
NS7 is far more superior than IE6.
I saw that Dr. Stockton has suggested me something
but I'll need time to see what it is. Thanks in advance.
Final solution:
DO NOT USE .tofixed
--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)
> I saw that Dr. Stockton has suggested me something
>but I'll need time to see what it is. Thanks in advance.
I have in js-round.htm a list of test values which seem good at bringing
out defects in various code for formatting numbers to strings.
It could be useful to have a number that illustrates each defect of
toFixed; also to have a careful description so accurate that it could be
used to write a matching toFixed.
Banker's rounding in toFixed(0) is not necessarily an unintentional
defect.
I don't agree. Do not use .toFixed should only be a
temporary solution, but not a _final_ solution. On one
hand, the standard suggests this method, and if it's badly
implemented, it's the fault of the implementor. Thus,
Microsoft has no excuse not to repair its fault.
On the other hand, actually I'm not the one who found
this bug. I've got to know it in a JavaScript mailing-
list. There're a lot of people out there using this
method without knowing this serious bug. It's the
implementor's responsibility to fix it.
You are right.
The only trouble is, that lots off bad fixes using .tofixed will create
havoc when half of the browsers are "fixed" and half not.
So do not use .tofixed till all updates have reached 99% of the users.
That will be in 5 years ????
Judging by (a) the nature of the problem, and (b) the amount of misunderstanding
displayed in this group, I seriously doubt whether *anyone* is exploiting the
error for some collateral purpose.
The more likely scenario is that the existing "fixes" are self-written
extensions to the language (or simple functions) that will continue to perform
correctly if/when Microsoft gets off its behind and corrects this deficiency.
And repairing the error will result in immediate relief for those of us who want
to use it on the SERVER side.
"Evertjan." wrote:
>
> The only trouble is, that lots off bad fixes using .tofixed
> will create havoc when half of the browsers are "fixed" and
> half not.
>
> So do not use .tofixed till all updates have reached 99% of
> the users.
--
It is no argument at all against repairing, because I never said it should
not be repaired.
It was my argument for not using it at all (Yes indeed clientside) for the
next 5 years.
It is a function I can do without easily, even serverside.
Ah - my mistake.
I agree with the premise. A bug in a major browser release (and I realize this
isn't strictly a browser issue) can hamstring developers for years while we wait
for the offending bug to gradually fade away.
> It is a function I can do without easily, even serverside.
Obviously, we all can. We've had to so far...
>-----Original Message-----
> [snipped]
You cannot.
If you have grown so big, you are .toofixed in the idea you know it all.
Would you like a moderator that only accepts your point of view?
Do you think jokes are bad taste in a NG?
Do you seriously think this bug comes as a surprise to MS?
I am very sorry for that I have not noticed this post early. There are so
many passional people discussing this question here so I think that it was
resolved early.
Now the problem is "how could we make Microsoft aware of this problem?". Is
it correct? I will report it to the product team as soon as possible. On
the other hand, if you want to get a response more quickly, you can submit
a service request for this issue. The instructions is listed at
http://support.microsoft.com/default.aspx?scid=fh;EN-US;CNTACTMS
If the product team confirms that it is a bug, you will not be charged.
Please let me know if there is anything else I can help you with regarding
this issue.
Best regards,
Jacob Yang
This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. ? 2003 Microsoft Corporation. All rights
reserved
I have reported this issue to the product team. You're right -- it is
totally broken for that range of values. I understand that this issue has
brought you much inconvenience and I am truly sorry for that.
The developer team argee to enter a bug against the sustaining engineering
team.
On the other hand, The script engines are in "sustaining engineering" mode.
Generally speaking we are fixing only serious security issues. Our ship
schedule is exceedingly constrained -- even if this ever gets fixed, it
will not be released until some future version of the operating system goes
out. Thank you for your understanding.
I would imagine that you is unwilling to wait until Longhorn. A workaround
is trivial though. If "toFixed" is broken, replace it with something that
works!
function BetterToFixed(digits)
{
if (digits == 0 && Number(this) >= 0.5 && Number(this) < 1.0)
return 1.0;
else
return this.OriginalToFixed(digits);
}
Number.prototype.OriginalToFixed = Number.prototype.toFixed;
Number.prototype.toFixed = BetterToFixed;
Now the "toFixed" method calls the workaround.
Indeed those words are currently on the MS Web site.
What, then, should (12.345).toFixed(2) give? It needs to be a
string with one digit before the point and two after, representing about
twelve and a third. Jacob?
There're IMO two points concerning this problem that I
hope it be solved ASAP.
1) For those web programmers who aren't aware of this
problem, it would be quite serious.
2) I'm wondering why only this range of values causes
problem. I'm afraid there're other ranges subjected to
other problems as well. Maybe the simpler method is to
follow the steps mentioned in ECMAScript specification.
Anyway, I would like to be informed whenever this bug
is fixed, eg as a HotFix or something else.
Have a nice weekend.
Fong
>.
>
MS: toFixed Method
Returns a string representing a number in fixed-point notation.
numObj.toFixed([fractionDigits])
Arguments
numObj
Required A Number object.
fractionDigits
Optional. Number of digits after the decimal point. Must be in the range
0 – 20, inclusive.
Remarks
The toFixed method returns a string representation of a number in fixed-
point notation. The string contains one digit before the significand's
decimal point, and must contain fractionDigits digits after it.
If fractionDigits is not supplied or undefined, the toFixed method
assumes the value is zero.
========================
So we can build it ourself:
<script>
function toFix2(d){
if(d<0||d>11)return "error"
n=''+Number(this)
if(d==0)return n.match(/-?\d*/)
a=n.match(/-?\d*?\./)
b=n.match(/\.\d*/)
if(a==null)
r=n+"."+"000000000000".substr(0,d)
else
r=a+(b+"000000000000").substr(1,d)
return r
}
Number.prototype.toFixed = toFix2;
// tests:
x=-2
document.write(x.toFixed(2)+"<br>")
x=-992.5
document.write(x.toFixed(2)+"<br>")
x=992.5888888
document.write(x.toFixed(0)+"<br>")
document.write(x.toFixed(2)+"<br>")
document.write(x.toFixed(4)+"<br>")
x=0
document.write(x.toFixed(6)+"<br>")
document.write(x.toFixed(-7)+"<br>")
</script>
>MS: toFixed Method
>Returns a string representing a number in fixed-point notation.
>Remarks
>The toFixed method returns a string representation of a number in fixed-
>point notation. The string contains one digit before the significand's
>decimal point, and must contain fractionDigits digits after it.
>So we can build it ourself:
// ourselves
>x=-992.5
>document.write(x.toFixed(2)+"<br>")
That requires more than one digit before the decimal point. You and
Microsoft cannot both be right, unless the meaning of "one" has changed.
BTW, ISTM that you have an incorrect upper limit for d.
A RegExp appears incompatible with MSIE4.
Sure. I will correct you, when you are writing in Dutch ;-)
>>x=-992.5
>>document.write(x.toFixed(2)+"<br>")
>
> That requires more than one digit before the decimal point.
> You and Microsoft cannot both be right,
> unless the meaning of "one" has changed.
I take it, that M$ ment AT LEAST one digit. As they mangled the
application, why trust them on the definition?
"Only one digit before the decimal sign" makes the method useless.
> BTW, ISTM that you have an incorrect upper limit for d.
Yes, should be 20 digits.
> A RegExp appears incompatible with MSIE4.
I know we disagree on principle, John. My idea is that not using new
possiblilities is detrimental to any development. Is people want to see
my pages correctly, they should update to IE6, or at least to 5.5.
Finally my regex coded .toFixed function was only to show the
possiblility of a regex hotfix, not a final solution, as the use of
.toFixed can be circumvented by other code.
I hope others (Han?) can refine my rough code.
>> A RegExp appears incompatible with MSIE4.
>
>I know we disagree on principle, John. My idea is that not using new
>possiblilities is detrimental to any development. Is people want to see
>my pages correctly, they should update to IE6, or at least to 5.5.
You are entitled to think that; but there are those who, for good
reasons or otherwise, do not use the latest browsers.
And there are authors, including myself, who think that it is a good
idea for their pages to be usable by such people. Some of these authors
will themselves be using more recent browsers, as you would apparently
wish.
That is one reason why, if code that is not compatible with earlier
browsers is presented, the limitation also needs to be pointed out - it
will not be as obvious to them as it probably is to you.
If the only faults in toFixed are in toFixed(0), then there is little
problem; toFixed(0) gives a decimal point followed by zero digits, which
is deprecated anyway.
And if so, something based on
function toFix3(d) {
return d==0 ? this.Math.round()+'.' : this.toFixed(d) }
might do.
I'm somewhat against overloading an existing faulty function with a
fixed version; on reading part of the resulting code, it may not be
clear that a fixed version is being used - especially if the fix is
applied in an include file.
So I'd prefer to add a method toFixedOK - which would obviate the
infinite-recursion question.
> So I'd prefer to add a method toFixedOK - which would obviate the
> infinite-recursion question.
Agree.