Converting code from using doubles to BigDecimal - double

I've been writing a CAD type program for fun in JAVA. The other day I wrote some code to define a line which was tangent to 2 circles. I've been checking my numbers with a commercial CAD program and they have been fairly close. Usually to the 9th decimal point. My results really only need to be stored in an array to 7 decimal points. After successfully defining the line tangent to the 2 circles, I decided to test it and define a point which was the intersection of the line and one of the circles.
In one case I got the result I was looking for, in another case I got no intersection. After looking at a few of the calculations I realized I was getting a very very small variation of maybe 9 or ten decimal places. I'm thinking of rewriting the code using BigDecimal.
This is a small snippet of some of the code I need to rewrite. Once I started it became much more cumbersome than I was wanting to do. I'm thinking about just converting the results using BigDecimal and using the original code unless there is an easy way to convert the following code to a BigDecimal type of format.
private float[] offsetLine(float lnx1, float lny1, float lnz1, float lnx2, float lny2, float lnz2, String direction, float offset) {
double deltax = Math.abs(lnx2 - lnx1);
double deltay = Math.abs(lny2 - lny1);
double lineLength = Math.sqrt(deltax * deltax + deltay * deltay);
double stepx = (offset * deltay) / lineLength;
double stepy = (offset * deltax) / lineLength;

Ok I'll answer my own question. Here's some code I dug up. I could only round to 6 decimal places to get the rounding I wanted. Once I did my calculations in double values I called the subroutine roundDbl
double checkRadius1 = Math.sqrt(((cir1x - offsetpts[0])*(cir1x - offsetpts[0])) + ((cir1y - offsetpts[1]) * (cir1y - offsetpts[1])));
double checkRadiusRounded = roundDbl(checkRadius1, 6); //round to 6 decimal places
public static Float roundDbl(Double dblValue, int decimalPlace) {
String tempDblString = Double.toString(dblValue);
String tempDbl = new BigDecimal(tempDblString).setScale(decimalPlace, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
return Float.valueOf(tempDbl);
}

Related

Failed to multiply double in dart

I got an error when trying to multiply a number with a floating point in dart. Does anyone know why this happens?
void main() {
double x = 37.8;
int y = 100;
var z = x * y;
print(z);
// 3779.9999999999995
}
In other languages ​​(C#/C++) I would have the result: 3780.0
This is completely expected because 37.8 (or rather, the 0.8 part) cannot be precisely encoded as a binary fraction in the IEEE754 standard so instead you get a close approximation that will include an error term in the LSBs of the fraction.
If you need numbers that are lossless (e.g. if you are handling monetary calculations) then check out the decimal package.
A simpler hack if your floating point number has sufficient bits allocated to the fraction to keep the erroroneous bits out of the way is to round off the number after your calculation to the number of decimal places that you care about.
You can use toStringAsFixed to control fraction digits.
void main() {
double x = 37.8;
int y = 100;
var z = x * y;
print(z.toStringAsFixed(1));
// 3780.0
}

Conversion from Float to CGFloat in Swift

I was converting Float => CGFloat and it gave me following result. Why It comes as "0.349999994039536" after conversion but works fine with Double => CGFloat?
let float: Float = 0.35
let cgFloat = CGFloat(float)
print(cgFloat)
// 0.349999994039536
let double: Double = 0.35
let cgFloat = CGFloat(double)
print(cgFloat)
// 0.35
Both converting “.35” to float and converting “.35” to double produce a value that differs from .35, because the floating-point formats use a binary base, so the exact mathematical value must be approximated using powers of two (negative powers of two in this case).
Because the float format uses fewer bits, its result is less precise and, in this case, less accurate. The float value is 0.3499999940395355224609375, and the double value is 0.34999999999999997779553950749686919152736663818359375.
I am not completely conversant with Swift, but I suspect the algorithm it is using to convert a CGFloat to decimal (with default options) is something like:
Produce a fixed number of decimal digits, with correct rounding from the actual value of the CGFloat to the number of digits, and then suppress any trailing zeroes. For example, if the exact mathematical value is 0.34999999999999997…, and the formatting uses 15 significant digits, the intermediate result is “0.350000000000000”, and then this is shorted to “0.35”.
The way this operates with float and double is:
When converted to double, .35 becomes 0.34999999999999997779553950749686919152736663818359375. When printed using the above methods, the result is “0.35”.
When converted to float, .35 becomes 0.3499999940395355224609375. When printed using the above method, the result is “0.349999994039536”.
Thus, both the float and double values differ from .35, but the formatting for printing does not use enough digits to show the deviation for the double value, while it does use enough digits to show the deviation for the float value.

Display Float In UILabel

I am having an issue with using a float in a UILabel.
float doubleNum;
floatNum = 10 / 20;
cashLabel.text = [[NSString alloc] initWithFormat:#"%f", floatNum];
If I use "floatNum = 10 / 10;" it correctly returns "1.000000000", however, if I put in "floatNum = 10 / 20" it returns "0.0000000". I have tried about everything I know and it does not work. I know it's a dumb mistake, but I can't figure it out.
Happy Holidays. :)
You need to cast one of the integer's to a float.
Try replacing the divisional line with:
float floatNum = (float) 10 / 20;
and you should get the correct answer.
Or if possible just use floats in your division:
float floatNum = 10.0f / 20.0f;
should also work
The issue here is that you are assigning floatNum the result of dividing one INTEGER by another. The result of 10 / 20 is indeed 0 and as a float, it appears as 0.0000000. In order to obtain a proper result, you need to either use a cast type to turn it into a float or add a .0 to one of the numbers. In division, if one of the numbers is a float (which is easily done by just adding a .0 to one of them), the result will be a float as well.
Normally, C performs "integer division" (basically, division without the remainder -- 10/3 is 3R1, so it yields 3).
When you type floatNum = 10/20, it does 10/20 = 0 (remainder 10).
To fix this, you have to tell the program that you're giving it floating point numbers. Try using:
floatNum = 10.0 / 20,
floatNum = 10 / 20.0, or
floatNum = float (10 / 20).
All of those should work.
try floatNum = 10.0f/20.0f (i.e. make sure the calculation is being done with floats rather than ints)
Consider following example to understand how floats work:
float a = 1/120;
float b = 1.0/120;
float c = 1.0/120.0;
float d = 1.0f/120.0f;
NSLog(#"Value of A:%f B:%f C:%f D:%f",a,b,c,d);
Output: Value of A:0.000000 B:0.008333 C:0.008333 D:0.008333
For float variable a : int / int yields integer which you are assigning to float and printing it so 0.0000000
For float variable b: float / int yields float, assigning to float and printing it 0.008333
For float variable c: float / float yields float, so 0.008333
Last one is more precise float. Previous ones are of type double: all floating point values are stored as double data types unless the value is followed by an 'f' to specifically specify a float rather than as a double.
Change your code to:
float floatNum;
floatNum = 10.0f / 20.0f;
cashLabel.text = [[NSString alloc] initWithFormat:#"%f", floatNum];

Round a float to 3dp?

How do I round a float to three decimal places?
I have this:
(round(1000.0f * currentHue) / 1000.0f)
Which rounds it to 3 decimal places but leaves a bunch of 0s on the end.
Most numbers can't be represented precisely with floating point. If you need precision that bad pick appropriate scientific library. If you want to print it nicely, use formatters -
NSLog(#"%.3f", currentHue);
This is a fairly hairy way to do it... But it should work.
float x = [[NSString stringWithFormat:#"%1.3f",(round(1000.0f * currentHue) / 1000.0f)] floatValue];

pi in Objective C

I keep getting error in my iPhone programing when I try to use pi. I'm trying
float pNumber = 100*cos(2 * pi * (days/23));
But i get errors that say:
_pi, referenced from
_pi$non_lazy_ptr
I saw somewhere on the internet to use M_PI and it compiles but I don't think it gives me the correct calculation.
When I try:
float pNumber = 100*cos(2 * M_PI * (15746/23));
I get 0
Thanks
The integer division probably needs to be coerced into a floating point one (cast one of the numbers to a double - or use the notation 23.0 to indicate that you want a floating point division).
Try printing out M_PI and see what it says (printf("M_PI = %16.9g\n", M_PI); in C).
Did you include the declaration for cos()? If not, it may be interpreted as a function returning an integer (#include <math.h> perhaps).
Example code (tested in C on Solaris 10 SPARC with GCC 4.3.3):
#include <math.h>
#include <stdio.h>
int main(void)
{
float pNumber = 100*cos(2 * M_PI * (15746/23));
printf("M_PI = %16.9g\n", M_PI);
printf("pNum = %16.9g\n", pNumber);
pNumber = 100*cos(2 * M_PI * (15746/23.0));
printf("pNum = %16.9g\n", pNumber);
return 0;
}
Example output:
M_PI = 3.14159265
pNum = 100
pNum = -77.5711288
C/C++ and hence Objective C/C++ does not promote integers to floats when doing normal division.
So in C/C++ the expression 15746/23 evaluates to 567, not to 567.71207 as you might naively expect.
C will promote integers to floats as necessary if one or other operand is a float, so all you need to do is use 15746.0 or 23.0 in your expression, ie change to
float pNumber = 100*cos(2 * M_PI * (15746/23.0));
The 100 will automatically be promoted because cos returns a float (actually a double, but I will ignorefloat/double percissions issues). The 2 is promoted to a float because M_PI is a float. And the 15746 is promoted to a float because 23.0 is a float.
However, it would not hurt to add the .0 to all the constants, ie:
float pNumber = 100.0*cos(2.0 * M_PI * (15746.0/23.0));
The problem is the integer division in the innermost part of the expression, which truncates the value (omitting the fractional part). One option, as mentioned, is to make every constant a floating point number, either by adding ".0" or "f" after it. Alternatively, you can omit the parentheses from the innermost expression entirely. Since M_PI is a floating point number, and multiplication in C is left-associative (meaning it proceeds from left to right) the first multiplication (2 * M_PI) will be promoted to a float, as will each successive multiply. Since cos() returns a float, pNumber will be assigned a float without having performed any integer division, hence no loss of precision. (Note: It's not usually wise to count on operator associativity or precedence, but in this case I'm just trying to demonstrate that it would in fact work.)
As far as the range of numbers you should expect to see, recall that the cosine (unmodified) ranges from -1 to +1, not 0 to 1, so you would actually see -100 to 100 (in theory). To get the correct range, you'd want to add 1, then multiply by 50.
Incidentally, the compile errors you get in the first case are because pi is not defined. The guidance to use M_PI is correct — for math constants, it's always smarter (and more consistent) to use what the system provides. If you're curious, on Leopard these constants are #defined in Math.h, lines 528-540. You can open the file by using File > Open Quickly... (Cmd-Shift-D) and typing "Math.h", or by double-clicking on M_PI in your code while holding down Command.
Why use a sinusoid in the first place ?
If the goal is to have a fonction ranging from 0 to 100 then 100 to 0 in 23 days, you could use:
// x ranges from 0 to 2
float x = (days % 23)/11.5;
// pNumber is a saw ranging from 0 to 100
float pNumber = 100 * abs(x - 1);
You can also replace the x by a cosine if you really want one, as 2*pi/23 ~= 0.273, you have
float x = 1 + cos((days % 23)*0.273);