I started learning processing since a short time ago and I came across a problem; When deviding 199.999 by 200 I want to outcome to be with 2 decimals (so the outcome should be 1 rounded of). Without formatting the outcome is 0.999995.
Code for formatting to String with 2 decimal:
float money = 199.999;
int munten = 200;
String calc1 = nf(money/munten,0,2);
println(calc1);
float calc2 = float(calc1);
println(calc2);
Prints:
1,0
NaN
I think float() wont work cause there is a comma in the String instead of a dot, I'm not sure tough. But how can I round a number to 2 decimal and still let it be a float?
Thanks for taking your time to read this,
When I run your example on Processing 3.3.6 / macOS 10.12 (US), I get "1.00" and "1.0". This could be due to your number formatting settings creating output strings that are then not read correctly by nf().
float money;
int munten;
String s;
float f;
money = 199.999;
munten = 200;
s = nf(money/munten, 0, 2);
println(s); // "1.00" -- or "1,0" etc. in different os language locales
f = float(s);
println(f); // "1.0" -- or NaN error if above is not 1.0 format
f = money/munten;
println(f); // 0.999995
s = nf(f, 0, 2);
println(s); // 1.00 -- or local format
You can see what should be happening more clearly in the second bit of code -- don't try to convert into a String and then back out again; don't store numbers in Strings. Instead, keep everything in numeric variables up until the moment you need to display.
Also keep in mind that nf() isn't really for rounding precision, although it is often used that way:
nf() is used to add zeros to the left and/or right of a number. This is typically for aligning a list of numbers. To remove digits from a floating-point number, use the int(), ceil(), floor(), or round() functions. https://processing.org/reference/nf_.html
If you need to work around your locale, you can use Java String formatting in Processing to do so:
float fval = 199.999/200;
println(fval); // 0.999995
String s = String.format(java.util.Locale.US,"%.2f", fval);
println(s); // 1.00
See https://stackoverflow.com/a/5383201/7207622 for more discussion of the Java approach.
Related
Keep in mind that Precision is based on the total number of digits and not the decimal places, but I need a way to set the Decimal places and all I can find is Precision, so I am trying to work with it, so I account for the number of digits in the whole number, in order to get this to work, but that is not working.
I want to do some math and return with a set precision value, the function takes a string of a very large number with a very large decimal precision and returns it as a string set to the number of decimals passed in as precision:
#include <boost/multiprecision/mpfr.hpp>
QString multiply(const QString &mThis, const QString &mThat, const unsigned int &precison)
{
typedef boost::multiprecision::number<mpfr_float_backend<0> > my_mpfr_float;
my_mpfr_float aThis(mThis.toStdString());
my_mpfr_float aThat(mThat.toStdString());
my_mpfr_float::default_precision(precison);
my_mpfr_float ans = (aThis * aThat);
return QString::fromStdString(ans.str());
}
I have tried it without the typedef, same problem;
MathWizard::multiply("123456789.123456789", "123456789.123456789", 20);
18 digits of Precision, 9 + 9, I should ask for 30
will return 22 decimal places
15241578780673678.51562
instead of 20
15241578780673678.516
So why is it off by 2?
I would like to make the precision change after the math, but it seems you have to set it before, and not like the examples that boost shows in their example, but still does not return the correct value, doing it after does not change value.
Update: Compare what I did to what they say works in this Post:
how to change at runtime number precision with boost::multiprecision
typedef number<gmp_float<0> > mpf_float;
mpfr_float a = 2;
mpfr_float::default_precision(1000);
std::cout << mpfr_float::default_precision() << std::endl;
std::cout << sqrt(a) << std::endl; // print root-2
I have noticed differences between gmp_float, mpf_float (using boost/multiprecision/gmp.hpp) and mpfr_float, and mpfr_float will give me a closer precision, for example, if I take the number (1/137):
mpf_float
0.007299270072992700729927007299270072992700729927007299270073
only 1 Precision, 23 digits when set to 13
0.00729927007299270072993
mpfr_float
0.007299270072992700729929
only 1 Precision, 16 digits when set to 13
0.0072992700729928
With only 1 Precision I would expect my answer to be have one less decimal.
The other data types do similar, I did try them all, so this code will work the same for all the data types described here:
boost 1.69.0: multiprecision Chapter 1
I also must point out that I rely on Qt since this function is used in a QtQuick Qml Felgo App, and actually I could not figure out to convert this to string without converting it to an exponent, even though I used ans.str() for both, my guess is that fromStdString does something different then std::string(ans.str()).
I figure if I can not figure his out, I will just do String Rounding to get the correct precision.
std::stringstream ss;
ss.imbue(std::locale(""));
ss << std::fixed << std::setprecision(int(precison)) << ans.str();
qDebug() << "divide(" << mThis << "/" << mThat << " # " << precison << " =" << QString::fromStdString(ss.str()) << ")";
return QString::fromStdString(ss.str());
I still could not get away without using QString, but this did not work, it returns 16 digits instead of 13, I know that is a different question, as such I just post it to show my alternatives do not work any better at this point. Also note that the divide function works the same as the multiply, I used used that example to show the math has nothing to do with this, but all the samples they are showing me do not seem to work correctly, and I do not understand why, so just to make the steps clear:
Create back end: typedef boost::multiprecision::number > my_mpfr_float;
Set Precision: my_mpfr_float::default_precision(precision);
Set initial value of variable: my_mpfr_float aThis(mThis.toStdString());
Do some math if you want, return value with correct Precision.
I must be missing something.
I know I can just get the length of the string, and if longer than Precision, then check if Precision + 1 is greater than 5, if so add 1 to Precision and return a substring of 0, Precision and be done with all this Correct way of doing things, I could even do this in JavaScript after the return, and just forget about doing it the Correct way, but I still think I am just missing something, because I can not believe this is the way this is actually supposed to work.
Submitted Bug Report: https://github.com/boostorg/multiprecision/issues/127
I am trying to format some numbers as a currency, with commas and 2 decimal places. I've found "github.com/dustin/go-humanize" for the commas but it doesn't allow for specifying the number of decimal places. fmt.Sprintf will do the currency and decimal formatting but not the commas.
for _, fl := range []float64{123456.789, 123456.0, 123456.0100} {
log.Println(humanize.Commaf(fl))
}
Results:
123,456.789
123,456
123,456.01
I am expecting:
$123,456.79
$123,456.00
$123,456.01
That would be what the humanize.FormatFloat() does:
// FormatFloat produces a formatted number as string based on the following user-specified criteria:
// * thousands separator
// * decimal separator
// * decimal precision
In your case:
FormatFloat("$#,###.##", afloat)
That being said, as commented by LenW, float (in Go, float64) is not a good fit for currency.
See floating-point-gui.de.
Using a package like go-inf/inf (previously go/dec, used for instance in this currency implementation) is better.
See Dec.go:
// A Dec represents a signed arbitrary-precision decimal.
// It is a combination of a sign, an arbitrary-precision integer coefficient
// value, and a signed fixed-precision exponent value.
// The sign and the coefficient value are handled together as a signed value
// and referred to as the unscaled value.
That type Dec does include a Format() method.
Since July 2015, you now have leekchan/accounting from Kyoung-chan Lee (leekchan) with the same advice:
Please do not use float64 to count money. Floats can have errors when you perform operations on them.
Using big.Rat (< Go 1.5) or big.Float (>= Go 1.5) is highly recommended. (accounting supports float64, but it is just for convenience.)
fmt.Println(ac.FormatMoneyBigFloat(big.NewFloat(123456789.213123))) // "$123,456,789.21"
There is a good blog post about why you should never use floats to represent currency here - http://engineering.shopspring.com/2015/03/03/decimal/
From their examples you can :
d := New(-12345, -3)
println(d.String())
Will give you :
-12.345
fmt.Printf("%.2f", 12.3456)
-- output is 12.34
I've written a simple Bag class. A Bag is filled with a fixed ratio of Temperature enums. It allows you to grab one at random and automatically refills itself when empty. It looks like this:
class Bag {
var items = Temperature[]()
init () {
refill()
}
func grab()-> Temperature {
if items.isEmpty {
refill()
}
var i = Int(arc4random()) % items.count
return items.removeAtIndex(i)
}
func refill() {
items.append(.Normal)
items.append(.Hot)
items.append(.Hot)
items.append(.Cold)
items.append(.Cold)
}
}
The Temperature enum looks like this:
enum Temperature: Int {
case Normal, Hot, Cold
}
My GameScene:SKScene has a constant instance property bag:Bag. (I've tried with a variable as well.) When I need a new temperature I call bag.grab(), once in didMoveToView and when appropriate in touchesEnded.
Randomly this call crashes on the if items.isEmpty line in Bag.grab(). The error is EXC_BAD_INSTRUCTION. Checking the debugger shows items is size=1 and [0] = (AppName.Temperature) <invalid> (0x10).
Edit Looks like I don't understand the debugger info. Even valid arrays show size=1 and unrelated values for [0] =. So no help there.
I can't get it to crash isolated in a Playground. It's probably something obvious but I'm stumped.
Function arc4random returns an UInt32. If you get a value higher than Int.max, the Int(...) cast will crash.
Using
Int(arc4random_uniform(UInt32(items.count)))
should be a better solution.
(Blame the strange crash messages in the Alpha version...)
I found that the best way to solve this is by using rand() instead of arc4random()
the code, in your case, could be:
var i = Int(rand()) % items.count
This method will generate a random Int value between the given minimum and maximum
func randomInt(min: Int, max:Int) -> Int {
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
The crash that you were experiencing is due to the fact that Swift detected a type inconsistency at runtime.
Since Int != UInt32 you will have to first type cast the input argument of arc4random_uniform before you can compute the random number.
Swift doesn't allow to cast from one integer type to another if the result of the cast doesn't fit. E.g. the following code will work okay:
let x = 32
let y = UInt8(x)
Why? Because 32 is a possible value for an int of type UInt8. But the following code will fail:
let x = 332
let y = UInt8(x)
That's because you cannot assign 332 to an unsigned 8 bit int type, it can only take values 0 to 255 and nothing else.
When you do casts in C, the int is simply truncated, which may be unexpected or undesired, as the programmer may not be aware that truncation may take place. So Swift handles things a bit different here. It will allow such kind of casts as long as no truncation takes place but if there is truncation, you get a runtime exception. If you think truncation is okay, then you must do the truncation yourself to let Swift know that this is intended behavior, otherwise Swift must assume that is accidental behavior.
This is even documented (documentation of UnsignedInteger):
Convert from Swift's widest unsigned integer type,
trapping on overflow.
And what you see is the "overflow trapping", which is poorly done as, of course, one could have made that trap actually explain what's going on.
Assuming that items never has more than 2^32 elements (a bit more than 4 billion), the following code is safe:
var i = Int(arc4random() % UInt32(items.count))
If it can have more than 2^32 elements, you get another problem anyway as then you need a different random number function that produces random numbers beyond 2^32.
This crash is only possible on 32-bit systems. Int changes between 32-bits (Int32) and 64-bits (Int64) depending on the device architecture (see the docs).
UInt32's max is 2^32 − 1. Int64's max is 2^63 − 1, so Int64 can easily handle UInt32.max. However, Int32's max is 2^31 − 1, which means UInt32 can handle numbers greater than Int32 can, and trying to create an Int32 from a number greater than 2^31-1 will create an overflow.
I confirmed this by trying to compile the line Int(UInt32.max). On the simulators and newer devices, this compiles just fine. But I connected my old iPod Touch (32-bit device) and got this compiler error:
Integer overflows when converted from UInt32 to Int
Xcode won't even compile this line for 32-bit devices, which is likely the crash that is happening at runtime. Many of the other answers in this post are good solutions, so I won't add or copy those. I just felt that this question was missing a detailed explanation of what was going on.
This will automatically create a random Int for you:
var i = random() % items.count
i is of Int type, so no conversion necessary!
You can use
Int(rand())
To prevent same random numbers when the app starts, you can call srand()
srand(UInt32(NSDate().timeIntervalSinceReferenceDate))
let randomNumber: Int = Int(rand()) % items.count
I have a data file where decimal points aren't specified for a decimal number. The number is just described in the layout for the data file as first 2 digits as real and next 2 digits as decimal and it varies for different fields, the real and decimal part
So an actual number 12345.6789 is specified as 123456789. When I want this to be rounded off to 2 decimal points to match the value in application, I use the below logic
Public Function Rounding(NumberValue, DecimalPoints, RoundOff)
Rounder= Roundoff+1
Difference = DecimalPoints - Rounder
NumberValue = Mid(NumberValue, 1, Len(NumberValue)-Difference)
RealNumber=Mid(NumberValue,1,Len(NumberValue)-Rounder)
DecimalNumber=Right(NumberValue,Rounder)
NumberValue = RealNumber&"."&DecimalNumber
NumberValue = Cdbl(NumberValue)
NumberValue = Round(NumberValue, Roundoff)
Rounding = FormatNumber(NumberValue,Difference+1,,,0)
End Function
However the problem with this logic is that I am not able to round off decimals when the number has 0 as the decimal value
For an Example, lets take 12345.0000 which I want to round off to 2 decimal points
My function returns it as 12345 whereas I want this to be returned as 12345.00
Any ideas on how this logic could be tweaked to get the desired output or is that not possible at all?
To get the decimal places, use the Formatnumber function. See http://msdn.microsoft.com/en-us/library/ws343esk(v=vs.84).aspx - the default is normally 2 decimal places, but it is region settings specific when using the defaults.
Your script also has a small issue if the decimalpoints variable matches the roundoff variable - it will not populate Rounding with a result. I am also not sure why you are comparing DecimalPoints to Roundoff (-1) ?
I've revised the entire routine - it should do what you want (although I don't know what values you are feeding it) - So now it will work like this:
Doing 4 digits:
Rounding (123450001, 4, 2)
Result:
12345.00
Doing 2 digits:
Rounding (123450001, 2, 2)
Result:
1234500.01
Doing 4 digits (increments if > .5)
Rounding (876512345678, 8, 4)
Result:
8765.1235
Revised simplified function that should do everything you are asking:
Public Function Rounding(NumberValue, DecimalPoints, RoundOff )
RealNumber = Mid(NumberValue, 1, Len(NumberValue)-DecimalPoints)
DecimalNumber = Round("." & Right(NumberValue,DecimalPoints), RoundOff)
Rounding = FormatNumber(RealNumber + DecimalNumber,RoundOff,,,0)
End Function
Here's a working version of your Function:
Public Function Rounding(NumberValue, DecimalPoints, RoundOff)
RealNumber=left(NumberValue,Len(NumberValue)-DecimalPoints)
DecimalNumber="." & Right(NumberValue,DecimalPoints)
NumberValue = RealNumber + DecimalNumber
NumberValue = Round(NumberValue,RoundOff)
Rounding = FormatNumber(NumberValue, RoundOff,,,0)
End Function
I'm pretty sure you won't be able to use the Round() function for what you need. Take a look at the FormatNumber() or FormatCurrency() functions as they have the option to "IncludeLeadingZero".
Take a look at the answer from the following link for more information:
vbscript round to 2 decimal places using Ccur
When we convert a float to integer in visual basic 6.0, how does it round off the fractional part? I am talkin about the automatic type conversion.
If we assign like
Dim i as Integer
i=5.5
msgbox i
What will it print? 5 or 6 ??
I was getting "5" a couple of months before. One day it started giving me 6!
Any idea whats goin wrong? Did microsoft released some patches to fix something?
Update : 5.5 gets converted to 6 but 8.5 to 8 !
Update 2 : Adding CInt makes no difference. CInt(5.5) gives 6 and Cint(8.5) gives 8!! Kinda weired behaviour. I should try something like floor(x + 0.49);
Part of this is in the VB6 help: topic Type Conversion Functions. Unfortunately it's one of the topics that's not in the VB6 documentation on the MSDN website, but if you've installed the help with VB6, it will be there.
When the fractional part is exactly 0.5, CInt and CLng always round it to the nearest even number. For example, 0.5 rounds to 0, and 1.5 rounds to 2. CInt and CLng differ from the Fix and Int functions, which truncate, rather than round, the fractional part of a number. Also, Fix and Int always return a value of the same type as is passed in.
Implicit type coercion - a.k.a. "evil type coercion (PDF)" - from a floating point number to a whole number uses the same rounding rules as CInt and CLng. This behaviour doesn't seem to be documented anywhere in the manual.
If you want to round up when the fractional part is >= 0.5, and down otherwise, a simple way to do it is
n = Int(x + 0.5)
And off the top of my head, here's my briefer version of Mike Spross's function which is a replacement for the VB6 Round function.
'Function corrected, now it works.
Public Function RoundNumber(ByVal value As Currency, Optional PlacesAfterDecimal As Integer = 0) As Currency
Dim nMultiplier As Long
nMultiplier = 10 ^ PlacesAfterDecimal
RoundNumber = Fix(0.5 * Sgn(value) + value * nMultiplier) / CDbl(nMultiplier)
End Function
Sample output:
Debug.Print RoundNumber(1.6) '2'
Debug.Print RoundNumber(-4.8) '-5'
Debug.Print RoundNumber(101.7) '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
Update: After some googling, I came across the following article:
It is not a "bug", it is the way VB was
designed to work. It uses something
known as Banker's rounding which, if
the number ends in exactly 5 and you
want to round to the position in front
of the 5, it rounds numbers down if
the number in front of the 5's
position is even and rounds up
otherwise. It is supposed to protect
against repeated calculation using
rounded numbers so that answer aren't
always biased upward. For more on this
issue than you probably want to know,
see this link
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q196652
This explains the (apparent) weird behavior:
Cint(5.5) 'Should be 6'
Cint(8.5) 'Should be 8'
Old Update:
Perhaps you should be more explicit: use CInt, instead of simply assigning a float to an integer. E.g:
Dim i as Integer
i = CInt(5.5)
MsgBox i
The changed behaviour sounds worrying indeed, however the correct answer surley is 6. Scroll down to "Round to even method" on Wikipedia, Rounding for an explanation.
As others have already pointed out, the "weird behavior" you're seeing is due to the fact that VB6 uses Banker's Rounding when rounding fractional values.
Update 2 : Adding CInt makes no
difference. CInt(5.5) gives 6 and
Cint(8.5) gives 8!!
That is also normal. CInt always rounds (again using the Banker's Rounding method) before performing a conversion.
If you have a number with a fractional part and simply want to truncate it (ignore the portion after the decimal point), you can use either the Fix or the Int function:
Fix(1.5) = 1
Fix(300.4) = 300
Fix(-12.394) = -12
Int works the same way as Fix, except for the fact that it rounds negative numbers down to the next-lowest negative number:
Int(1.5) = 1
Int(300.4) = 300
Int(-12.394) = -13
If you actually want to round a number according to the rules most people are familiar with, you will have to write your own function to do it. Below is an example rounding that will round up when the fractional part is greater than or equal to .5, and round down otherwise:
EDIT: See MarkJ's answer for a much simpler (and probably faster) version of this function.
' Rounds value to the specified number of places'
' Probably could be optimized. I just wrote it off the top of my head,'
' but it seems to work.'
Public Function RoundNumber(ByVal value As Double, Optional PlacesAfterDecimal As Integer = 0) As Double
Dim expandedValue As Double
Dim returnValue As Double
Dim bRoundUp As Boolean
expandedValue = value
expandedValue = expandedValue * 10 ^ (PlacesAfterDecimal + 1)
expandedValue = Fix(expandedValue)
bRoundUp = (Abs(expandedValue) Mod 10) >= 5
If bRoundUp Then
expandedValue = (Fix(expandedValue / 10) + Sgn(value)) * 10
Else
expandedValue = Fix(expandedValue / 10) * 10
End If
returnValue = expandedValue / 10 ^ (PlacesAfterDecimal + 1)
RoundNumber = returnValue
End Function
Examples
Debug.Print RoundNumber(1.6) '2'
Debug.Print RoundNumber(-4.8) '-5'
Debug.Print RoundNumber(101.7) '102'
Debug.Print RoundNumber(12.535, 2) '12.54'
The VB6 Round() function uses a Banker's Rounding method. MS KB Article 225330 (http://support.microsoft.com/kb/225330) talks about this indirectly by comparing VBA in Office 2000 to Excel's native behavior and describes it this way:
When a number with an even integer ends in .5, Visual Basic rounds the number (down) to the nearest even whole number. [...] This difference [between VBA and Excel] is only for numbers ending in a .5 and is the same with other fractional numbers.
If you need different behavior, I'm afraid you'll have to have to specify it yourself.