Math in JS.
Can anyone please go through the code and let me know why converting from dollar to cents gives wrong result
Steps:
$32.5:Converting to cent->32*100=3200.
value after decimal point is cent =0005.
$10 to be charged extra if cost is less than $40 so $10 gets converted into cents as =1000
Summing up all the above three values we get in cents=4205.
convert back to dollars=4205/100=$42.05.This is the process used to convert manually.
but in reality ans should be $42.5.
https://codepen.io/kvandana451/pen/wvLjBEa
89 Replies
There are a few issues with your code but my main question is, why do you even need to split it?
something like this would return the value that you want with out any need to extract the decimal value:
For floating point nos to avoid inaccuracies.
what inaccuracies are you envisaging? Either the number is below 40 or it isn't, with or without decimals.
32.5
"32.5" would work fine with the code that I posted.
yes. But its suggested to convert float number into cents to prevent inaccuracies
Manually we do it like this with pen and paper.
7.99 gives 17.9900002
Ok, I see
You probably want .toFixed() to handle that kind of stuff. There's a good example on MDN
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed
MDN Web Docs
Number.prototype.toFixed() - JavaScript | MDN
The toFixed() method of Number values returns a string representing this number using fixed-point notation with the specified number of decimal places.
Since the problem lies in the display of the value, and not the value itself.
There are two errors in this function
1. Obtaining the value of decResult
2. Calculation formula for <40
First, let’s talk about problem 1:
You will find that your input may have one or two decimal places.
When there are two decimal places, the value calculated by decResult is correct.
When there is one decimal place, decResult is obviously incorrect, which is why the final result is wrong
—————————————————————————————
Decimal part Actual Expected
—————————————————————————————
0.99 99 99
0.05 5 5
0.5 5 50
—————————————————————————————
Let’s talk about problem 2:
The following is your code
You will find that your calculation formula is the same as directly [num + 10], there is no difference,
because you finally take a floating point number for calculation,
instead of converting it into a floating point number that is 100 times smaller after the calculation is completed
As Kirin-808 said, You probably want .toFixed() to handle that kind of stuff.
This is not correct. The + happens BEFORE the parse. This results in concatenation and the parse happens AFTER that. Consider for example if num is "5". What happens is ("5" + 10) is calculated before parsing, and the result of that is the string "510". Parsing that would be the number 510 instead of 15.
how about you don't do any parsing?
first, make sure it only has 2 decimal places:
value.replace(/\.(\d\d?)?.*$/, '.$1')
emm....
This should not happen, because the first line of the function performs the number conversion operation.
that's horrible, and obliterates accuracy
if you use floats at all, at any point, it's ruined
you have to handle it as a string, to do not lose accuracy
this is a solution that parses the number as a string
step 1:
.replace(/(?:[.,]0|[.,]?)$/, '.00')
- for something like 12
or 12.
or 12.0
, makes it into 12.00
- for something like 12.00
, makes it into 12.00.00
(for performance reasons)
step 2: .replace(/[.,](\d\d?)?.*$/, '.$1')
- for something like 12.00
or 12.00.00
, makes it into 12.00
- for something like 12.3
, makes it into 12.3
- for something like 12.3456789
or 12.344444444444
, makes it into 12.34
step 3: .replace(/[.,](\d)$/, '.$10')
- for something like 12.3
, makes it into 12.30
- for something like 12.00
, makes it into 12.00
step 4: remove decimal point
E.g.:
- 12.00
> 12.00.00
> 12.00
> 1200
- 12345.6
> 12345.6
> 12345.60
> 1234560
- 9876.54321
> 9876.54321
> 9876.54
> 987654
- 1
> 1.00
> 1.00
> 100
with absolutely 0 precision loss, converts a decimal number to an integer one multiplied by 100OK. I didn't notice that Number conversion. If that happens, then the parse is completely unnecessary.
i found a simpler method:
Another simple method which can be understandable?
that is splitting the string by the decimal separator, then multiplies the left side by 100, makes the right side be between 0 and 99 and adds it to the left side
without going into precision loss, i cant think of something better
You mean this?
yes, that
it parses the decimal dollar value into cents
and with cents, you can do your math
if you use decimals, you're just doing it wrong
just remember the classic 0.1 + 0.2 not being the same as 0.3
you can just
Math.round(parseFloat('1234.56') * 100)
that parses as a float
already has innacuracies
not enough of an inaccuracy to change the final value
round returns an int
but probably will be ok for 99.9999% of the times
no, 100%. There's not a single reasonable situation where a float is so inaccurate that it's off by 0.005
when you're dealing with currency at least
ive had troubles with rounding errors
with 2 decimal places
and even with 4, but 4 helped a lot
when you start adding things as floats sure, but with a single conversion at the start?
it's possible
im going overkill and skipping all possibilities
hmm... then use a regex to validate that there's two decimal places and
.replace
the point out, then parseInt 😄this does that, but without regex
this does that, with regex and support for comma or period for decimals
both options guarantee that you have 2 decimal places, and then return an usable integer number
none do rounding, only truncating
yeah, fair. It's still massive overkill for almost all situations
at worst it'll be off by 1 cent
and that's only if you're talking about billions of dollars, if not trillions
yes, but 1 cent is enough to be wrong
no one gives a shit about 1c if you're paying a trillion dollars for something
but ... you are right, it is overkill for this situation
still the correct way!
For reference, rounding a parsefloat*100 is what I've used for software that's processed over 3M invoices and it's never gone wrong
and that includes invoices north of $1M
i would be scared as hell of using any of these solutions
but, i cant deny it: it works
(and again, no one gives a shit about 1c in the accounting world)
you sure? 🤔
no one I've worked with at least
there's a ton of things where you get say... 21% VAT, and you have a net and gross and VAT amount
i think companies have a percentage of error that is acceptable, without paying fines, right?
there's situations where net and 21% net don't add up to a whole cent value. Some invoicing software uses floor, others ceil, or round. Or the net is calculated from the gross, because $25 looks a lot better on a price sticker than $25.03
and then there's occasionally discount amounts for paying on time, so say another 7% off if you pay by the due date, and there's rounding-cents lost everywhere
so yeah, no one cares if you pay $0.01 too much or too little
alright, that makes sense
yeah, that too. My dad tried rounding down to the nearest whole € for a while for all the invoices he paid, no one cared
so yeah, round(parsefloat() * 100) is more than fine for pretty much anything to do with currency
just minimize the amount of math you do with floats
yes, minimize it to 0
no math with floats, if you need precision
or use fixed-point decimals, if they are fast
like mysql's decimal thingy
I didn't read this thread closely, but that greedy dot star set off alarms
capture the optional 2 characters first I guess, avoid the performance hit of parsing an n-length number, if that's the only risk...
it's just to truncate to 2 decimal numbers
yes
if you have
0.05892897298217329832178129387313289312781313982712313289123713289132781321839132713291327891327132897132
, you get 0.05
it's not rounding: it's truncatingyes, but the regex engine will still evaluate the rest of the string, which could be any length
yes, it will
it has to, sadly
which is why i found a better solution
and if it's a very long number it's a performance hit, or a malicious way to slow a program.
yes, it is
regex is the best (not literally, just ❤️ ) , so dropping regex for a readable, accurate, safe solution isn't really better... it's just better.
basically, the string will have to be about 20000 characters long to take 8.8ms to parse the number
i love regex, so, i went first with a regex solution
Holy F JS has a large string size limit, chrome allows a 2^29 - 24 elements (~1 GiB)
I imagined you would also be a regex fan 🙂
no no, not a fan: a lover
i do some cursed stuff with it too, like, validating numbers
without regex. I didnt use parse, i used Number to convert the string to number.Kindly go through.
..
kept this in mind.
@ἔρως @Jochem waiting for the update.
that's not going to work properly
^ this has a bug: you're creating a global variable, and there's the tiny tiny tiny tiny possibility that it changed between declaration and usage
also, you have repeated text
also, innerText replaces all elements, contrary to textContent
also, the
else
is useless
and the num >= 0
is useless tooyou mean num variable?
no,
res = num
creates a global variablebut then res can be used inside the if statement only its a scoped variable.
it's global
some events can stop the execution of the code
and the variable can be changed outside the function
but still
it's mostly repeated code
this does the same
same as innerText right?
so you mean variables declared using let inside scopes {} can become global due to some events?
no, it isn't. innerText replaces everything with a text node, while textContent replaces just the text
it's the lack of
var
or let
or const
so this is unavoidable right?
it's super avoidable
just add one of those and it's no longer global
inEq1 its declared using let only
not in the
else
so can you please tell me where innerHTML AND innerText is applicable correctly.lot many times i noticed they are not applied correctly in projects
now-a-days, nearly nowhere
innerHTML is only a "good" idea if you want to delete everything inside an element, but even then, there's better options
okay inside the elements u mean text,else attributes etc right
what are you talking about?
delete everything inside an element, meaning elements text ,attributes
nodes
attributes are part of elements
all elements are nodes
text is also a node, but not an element
and comments are nodes too, but also not elements
doing
document.getElementById('test').innerHTML = '';
would remove "Hello World." but leave the ID alone. InnerHTML only affects the contents of a node, which is the part between the >
on the opening tag and the <
on the ending tag.
updated as per this.
at least indent the code
and the else is useless
eq1 solves the pbm of inaccuracy right . Rather than regEx
no, but it is acceptable
that means when we are encountering decimal nos we can go ahead with toFixed(n) else multiplying the digit with 100(if we want two decimals places) then math.round then divide it back by 100.Both methods give same result which is accepatable
there's another bug in this: it doesn't limit to 2 decimal places if the input has more than 2
give me an example please to reproduce the issue.
45.6789
that should bug it
yes thanks for pointing it and go through the code.
i will check it later
I can't go through the code right now, but I will say one thing: Please format your code properly. The interpreter doesn't care about indenting, but it makes it so much harder to read. It's a little bit of extra effort, unless you use some kind of autoformatting which you can easily set up in VS Code and in Codepen, but it makes debugging and reading your code 10x easier
and honestly, if I had an applicant show me their code and the indentation was all over the place, that's an instant rejection.