Adding two numbers don't get correct result - actionscript-3

I try to add two numbers, but don't get correct result
var n1:Number = 2785077255;
var n2:Number = 100000097214922752;
trace(Number(n1 + n2));//trace 100000100000000000, not 100000100000000007
trace((Number.MAX_VALUE - Number(n1 + n2)) > 100);//trace true
When I got the wrong result, I thought it exceed the Number's max value,so I test it and it doesn't trace false as I thought.

Yes, the problem is in Number as #Phylogenesis mentioned, it's actually 64 bit double with 52 bits for mantis, but your result exceededs that.
The good news are that there is a workaround for that, event two :)
Use some BigInteger/LongInt AS3 impelementation (you can google several of them), for instance BigInteger from as3crypto, or LongInt from lodgamebox
It's currently only for multiplying, but you can modify that solution as a small task. For best performance (without creation of temporary arrays/byte arrays) you can use that utility method that I created once (it's based on LongInt from lodgamebox library)
/**
* Safe multiplying of two 32 bits uint without precision lost.
*
* Usage:
* Default behaviour (with 64 bit Number mantis overflow):
* uint(1234567890 * 134775813) = 1878152736
*
* Fixed correct result by that method:
* uint(1234567890 * 134775813) = 1878152730
*
* #param val1
* #param val2
* #return
*
*/
public static function multiplyLong(val1:uint, val2:uint):uint
{
var resNum:Number = val1*val2;
//52 bits of mantis in 64 bit double (Number) without loose in precision
if(resNum <= 0xFFFFFFFFFFFFF)
return uint(resNum);
//count only low 32 bits of multiplying result
var i:uint, mul:Number, ln:uint=0, hn:uint=0, _low:uint = val1;
for (i = 1<<31; i; i >>>= 1)
{
if(val2 & i)
{
mul = _low * i;
ln += mul & uint.MAX_VALUE;
}
}
_low = ln;
return _low;
}

Related

in SAS proc fcmp how to get 2 numbers returned

I have a function that should return 2 numbers (geographic coordinates).
Is it possible to get the function to return 2 numbers?
Here is my function (I need to return x and Y)
proc fcmp outlib=common.functions.geo;
function latlng2lambert72(lat,lng);
LongRef = 0.076042943;
bLamb = 6378388 * (1 - (1 / 297));
aCarre = 6378388 ** 2;
eCarre = (aCarre - bLamb ** 2) / aCarre;
KLamb = 11565915.812935;
nLamb = 0.7716421928;
eLamb = sqrt(eCarre);
eSur2 = eLamb / 2;
*conversion to radians;
lat_rad = (constant("pi") / 180) * lat;
lng_rad = (constant("pi") / 180) * lng;
eSinLatitude = eLamb * sin(lat_rad);
TanZDemi = (tan((constant("pi") / 4) - (lat_rad / 2))) *
(((1 + (eSinLatitude)) / (1 - (eSinLatitude))) ** (eSur2));
RLamb = KLamb * ((TanZDemi) ** nLamb);
Teta = nLamb * (lng_rad - LongRef);
x = 150000 + 0.01256 + RLamb * sin(Teta - 0.000142043);
y = 5400000 + 88.4378 - RLamb * cos(Teta - 0.000142043);
*put x y ;
return (x);
*return (x*1000000000000 + y);
*return (x||'_'||y);
endsub;
quit;
data test;
lat = 50.817500;
lng = 4.374400;
x = latlng2lambert72(lat,lng);
run;
I guess not but then the only option I see would be to make 2 functions and have one return the 1st number and the other return the 2nd number. These 2 functions would be 99% identical and I don't like to duplicate code. Is there a more efficient way to achieve this?
(I don't really understand how subroutines work. Could they be used to that end? Execute the common code and just make 2 short functions to return x and y?)
Functions by definition return a single value; that's the definition of a function. It should be able to be on the right hand side of an equal sign.
Subroutines, in SAS known as Call routines, are able to "return" zero, one, or more values. They do this by not returning anything directly (you cannot put a call routine on the right-hand side of an equal sign), but by modifying the arguments they are called with.
You see this in routines like call missing, which can set any number of values to missing; you see it a bit more directly in routines like call scan, which tells you the start position and length of the nth word in a string.
In order to do this, then, you would first want to change your function to a subroutine/call routine, i.e. replace function with subroutine, and then specify OUTARGS.
An example of this would be:
proc fcmp outlib=work.funcs.func;
subroutine roots(inval, outval_pos, outval_neg);
outargs outval_pos,outval_neg; *specifies these two will be "returned";
outval_pos = sqrt(inval);
outval_neg = -1*outval_pos;
endsub;
quit;
options cmplib=work.funcs;
data _null_;
x=9;
call missing(y_pos,y_neg);
call roots(x,y_pos, y_neg);
put x= y_pos= y_neg=;
run;

Using google s2 library - find all s2 cells of a certain level within the circle, given lat/lng and radius in miles/km

What S2Region should i use and how should i use it to get all cells within a circle given a latitude, longitude and a radius in miles/km using google's s2 library?
S2Region region = ?
S2RegionCoverer coverer = new S2RegionCoverer();
coverer.setMinLevel(17);
coverer.setMaxCells(17);
S2CellUnion covering = coverer.getCovering(region_cap);
Thanks
Here's a C++ example from the npm package s2geometry-node. The code was copied from viewfinder/viewfinder.cc
const double kEarthCircumferenceMeters = 1000 * 40075.017;
double EarthMetersToRadians(double meters) {
return (2 * M_PI) * (meters / kEarthCircumferenceMeters);
}
string CellToString(const S2CellId& id) {
return StringPrintf("%d:%s", id.level(), id.ToToken().c_str());
}
// Generates a list of cells at the target s2 cell levels which cover
// a cap of radius 'radius_meters' with center at lat & lng.
vector<string> SearchCells(double lat, double lng, double radius_meters,
int min_level, int max_level) {
const double radius_radians = EarthMetersToRadians(radius_meters);
const S2Cap region = S2Cap::FromAxisHeight(
S2LatLng::FromDegrees(lat, lng).Normalized().ToPoint(),
(radius_radians * radius_radians) / 2);
S2RegionCoverer coverer;
coverer.set_min_level(min_level);
coverer.set_max_level(max_level);
vector<S2CellId> covering;
coverer.GetCovering(region, &covering);
vector<string> v(covering.size());
for (size_t i = 0; i < covering.size(); ++i) {
v[i] = CellToString(covering[i]);
}
return v;
}
I had encountered the same task and solved it with the usage of S2RegionCoverer.getCovering(S2Region region, ArrayList<S2CellId> covering) method.
The problem why you were getting cells of a different levels is described in S2RegionCoverer.getCovering(S2Region region) documentation:
/**
* Return a normalized cell union that covers the given region and satisfies
* the restrictions *EXCEPT* for min_level() and level_mod(). These criteria
* cannot be satisfied using a cell union because cell unions are
* automatically normalized by replacing four child cells with their parent
* whenever possible. (Note that the list of cell ids passed to the cell union
* constructor does in fact satisfy all the given restrictions.)
*/

Can someone explain this code for me? Base-Conversion Code

So for a homework assignment we had to make a program that converted a number from one base to another (i.e. 110 in base 2 to 6 in base 10). I asked my friend how he did his because I was having trouble and he just sent me his code and nothing else. Can someone explain the logic of this code so that I can make my own program and actually understand how to do this problem. Thanks!
import java.util.*;
public class Base_Converter {
public static final String value = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static void main(String args[]){
int x, y;
String num, base10 = "";
Scanner scan = new Scanner(System.in);
System.out.println("Enter a number you want to convert.");
num = scan.nextLine();
num = num.toUpperCase();
System.out.println("What base is it in?");
x = scan.nextInt();
System.out.println("What base do you want to convert it to?");
y = scan.nextInt();
if(x <= 36 && y <= 36 && x > 1 && y > 1){
base10 = toBase10(num,x);
num = newBase(base10,y);
System.out.println(num);
}
}
public static String toBase10(String num, int from){
long total = 0;
int counter = num.length();
char[] stringArray = num.toCharArray();
for(char w : stringArray){
counter--;
total += value.indexOf(w)*Math.pow(from,counter);
}
return String.valueOf(total);
}
public static String newBase(String num, int to){
String total = "";
int current = 0;
while(Integer.valueOf(num) > 0){
current = Integer.valueOf(num)%to;
total = value.charAt(current)+total;
num = String.valueOf(Integer.valueOf(num)/to);
}
return total;
}
}
I think you should be focusing not on what your friend's code does, but instead with how to do the assignment yourself, because I think your problems lie with a lack of understanding on your part. Instead of leaving you high and dry though I'll walk you through some of the specifics of base-conversion.
First, read user input. It looks like you're using Java, so just use a scanner to do this. At minimum you'll want to read the number you're converting, what base it is in, and what base the output will be in.
Next, we want to convert the number. You could directly convert numbers to each other (i.e. converting base 2 to base 8) but that requires more brainpower than I am willing to offer right now. Instead, I would suggest always first converting the user-inputted number to base 10 (much like your friend did). So how do we convert a number of an unknown base to base 10?
So let's break down how a number is represented: lets say we have the number 234 in base ten. This is equivalent to 4*10^0 + 3*10^1 + 2*10^2 or 4 + 30 + 200 = 234. You can use this same conversion for any other numbers. I.E. if the number is 1763 in base 8, the value in base 10 will be 3*8^0 + 6*8^1 + 7*8^2 + 1*8^3 or 3 + 48 + 448 + 512 = 1011 base 10(try entering 1763 here for proof. So to convert to decimal, you just need to see to multiply each individual number time your base to the power of its place minus 1. For example, since 1 is the fourth number in the 1763 you multiply it times 8^(4-1). Since, you are reading a string from the user. You'll need to convert each character of the string to an integer using the ascii chart.
Now to convert from base ten to anything. Instead of multiplying, you just divide each value and write the remainder! I'll let someone else describe this procedure.
Now just store this new value as a string doing somethings like
String output = "";
output += newValue;
In computer science, just copying someone else's code is way more harmful than helpful. Hope this helps!

Bogus math with app scripts

Anyone had an issue with bogus math results when using Google Apps Script? The following is the code, where a/b/c are send from another function. A/b/c are verified with the logger. ? StartPt is fine, but endpt is generating a false value.
function calcTime(a,b,c) {
var x;
var startHr = 8;
var startMin = 0;
var startSec=0;
var startPt;
var endPt;
startPt = (startHr * 60) + startMin + (startSec/60);
endPt = (a * 60) + b + (c/60);
Logger.log(endPt);
x = endPt -startPt;
return x;
}
flag
I found that the math error is a multiplication factor of 100 (when endPt is calculated, it multiplies the result by 100). What could cause this?
Real number arithmetic is prone to rounding errors in javascript and apps-script. See Is floating point math broken?. If you're watching your function in the debugger, you'll see rounding errors esp. with (c/60). But that's not likely causing a factor-of-100 error.
Most likely, your parameters aren't what you thing they are. If b arrives as a string, for instance, the calculation of (a * 60) + b + (c/60) will effectively ignore b. The other two parameters, however, will get changed to numbers to to complete the multiplication and division operations. (You can avoid that by using b * 1.)
Anyway, to confirm what you're getting as parameters, try replacing the first few lines of your function with this:
function calcTime(a,b,c) {
var params = {
a:{type:typeof a, value:a},
b:{type:typeof b, value:b},
c:{type:typeof c, value:c}}
Logger.log(params);
var x;
...
Verify that you're getting what you need. If any of the parameters are arriving as date objects, for instance, your math will be wildly incorrect. You may just need to enforce types for your data source.

Reduce number of decimals

In AS3, from a division I get a number like this one: 0.9130406010219044.
Is there any way to reduce the number of decimals (aside from multiplying that number for one million)? Is there a way to reduce the numbers BEFORE the division is performed?
Got the following function from this link, which rounds to an arbitrary number of decimals:
public function trim(theNumber:Number, decPlaces:Number) : Number {
if (decPlaces >= 0) {
var temp:Number = Math.pow(10, decPlaces);
return Math.round(theNumber * temp) / temp;
}
return theNumber;
}
// Round a number to two decimal places trace(trim(1.12645, 2));
// Displays: 1.13
Note: I slightly changed the function definition by adding types. See the link for explanation and original source code. Also made it return theNumber if decPlaces is less than or equal to zero.
var myNumber:Number = 74.559832;
trace(myNumber.toFixed(4)); //74.5598
trace(myNumber.toFixed(2)); //74.56
AS3 Documentation: Number class
If you just want to display the result (you didn't specify) then a simple bit of String manipulation will yield the fastest result:
0.9130406010219044.toString().substr(0, 4); // 0.91
Take a look at NumberFormatter.fractionalDigits
Or, if you're working in Flex: mx:NumberFormatter.precision / s:NumberFormatter.fractionalDigits
Try some of the answers here on for size:
How to deal with Number precision in Actionscript?
If you use a NumberFormatter, make sure to specify rounding (it's most likely you'll want nearest).
If you need Number as result and performance, I would say this solution is more efficient than the Math.pow()
If you need 3 decimals just change 100 by 1000.
var myNumber:Number = 3.553366582;
myNumber = (( myNumber * 100 + 0.5) >> 0) / 100;
//trace = 3.55
demonstrating the rounding :
var myNumber:Number = 3.557366582;
myNumber = (( myNumber * 100 + 0.5) >> 0) / 100;
//trace = 3.56
Regarding the Number.toFixed() returning a String I guess it's because it returns 2 decimals in any case:
For instance :
Number(3).toFixed(2); // trace 3.00 so it has to be a String.