Commit 382562aa authored by Eva Darulova's avatar Eva Darulova

merging relative error computation with newest master

parents a4643d84 8f53156d
Copyright (c) 2017 MPI-SWS, unless otherwise specified. All rights reserved.
This software was developed by the Automated Verification and Approximation (AVA)
group of the Max Planck Institute for Software Systems (MPI-SWS), Saarbruecken
and Kaiserslautern, Germany.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of MPI-SWS.
\ No newline at end of file
......@@ -9,8 +9,7 @@ scalaVersion := "2.11.6"
scalacOptions ++= Seq(
"-deprecation",
"-unchecked",
"-feature"
)
"-feature")
resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
......@@ -22,8 +21,13 @@ libraryDependencies ++= Seq(
"org.fusesource.hawtjni" % "hawtjni-runtime" % "1.9" //for JNI
)
envVars := Map("LC_NUMERIC" -> "en_US.UTF-8")
Keys.fork in run := true
javaOptions in run ++= Seq(
"-Xms256M", "-Xmx2G", "-XX:+UseConcMarkSweepGC")
Keys.fork in Test := true //for native libraries to be on correct path
val scalaMeterFramework = new TestFramework("org.scalameter.ScalaMeterFramework")
......@@ -78,11 +82,16 @@ script := {
|
|SCALACLASSPATH="$paths"
|
|TMP=$$LC_NUMERIC
|LC_NUMERIC=en_US.UTF-8
|
|java -Xmx2G -Xms512M -Xss64M -classpath "$${SCALACLASSPATH}" -Dscala.usejavacp=false scala.tools.nsc.MainGenericRunner -classpath "$${SCALACLASSPATH}" daisy.Main $$@ 2>&1 | tee -i last.log
|
|LC_NUMERIC=$$TMP
|""".stripMargin)
f.setExecutable(true)
} catch {
case e: Throwable =>
s.log.error("There was an error while generating the script file: " + e.getLocalizedMessage)
}
}
\ No newline at end of file
}
Baseline sample size: 10000000
MidSample sample size: 50000
SmallSample sample size: 256
\ No newline at end of file
/* Copyright 2015 EPFL, Lausanne */
// Original work Copyright 2009-2016 EPFL, Lausanne
// Modified work Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy.lang
......@@ -8,8 +9,6 @@ import scala.annotation.StaticAnnotation
import scala.language.implicitConversions
import scala.math.{ScalaNumericConversions, ScalaNumber}
//import daisy.annotation._
@ignore
class ignore extends StaticAnnotation
......
/* Copyright 2015 EPFL, Lausanne */
package daisy
import scala.annotation.StaticAnnotation
package object annotation {
@ignore
class library extends StaticAnnotation
@ignore
class verified extends StaticAnnotation
@ignore
class main extends StaticAnnotation
@ignore
class extern extends StaticAnnotation
@ignore
class ignore extends StaticAnnotation
}
This directory will contain generated scala code from daisy.
Filenames will be the same as your input files.
Files are generated with the "--printToFile" flag.
I am a placeholder.
Daisy generated code will appear here.
\ No newline at end of file
Placeholder to keep the data/ folder alive.
\ No newline at end of file
This diff is collapsed.
#!/bin/bash
# To be run from /daisy
printf "Running cloc:\n"
cloc src/ | grep -E "(Language|Scala)"
printf "\n# asserts, requires, ensuring:"
grep -r -E "(assert|require|ensuring)" src/ | wc -l
printf "\nRunning Scalastyle:\n"
sbt scalastyle | grep "Found"
printf "\nRunning Abide:\n"
#sbt abide
files code comment blank Scalastyle warnings
12 June 2015: 38 7445 745 1945 1295
/*
The contents of this file is heaviy influenced and/or partly taken from
the Leon Project which is released under the BSD 2 clauses license.
See file LEON_LICENSE or go to https://github.com/epfl-lara/leon
for full license details.
*/
// Original work Copyright 2009-2016 EPFL, Lausanne
// Modified work Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
import scala.collection.immutable.Seq
import scala.reflect.ClassTag
import lang.Trees.Expr
import lang.Identifiers._
import utils.{Interval, PartialInterval, Rational}
import tools.{Interval, PartialInterval, Rational}
case class Context(
reporter: Reporter,
......@@ -21,22 +17,30 @@ case class Context(
files: Seq[String],
timers: TimerStorage = new TimerStorage,
libFiles: Seq[String] = Seq(
//"library/annotation/package.scala",
"library/lang/Real.scala"
"library/Real.scala"
),
// Information we want to persist through phases,
// but don't want to pollute the nice and clean trees.
// If these get too many, move to their own "Summary".
// indexed by FunDef.id
inputRanges: Map[Identifier, Map[Identifier, Interval]] = Map(),
inputErrors: Map[Identifier, Map[Identifier, Rational]] = Map(),
specInputRanges: Map[Identifier, Map[Identifier, Interval]] = Map(),
specInputErrors: Map[Identifier, Map[Identifier, Rational]] = Map(),
// for now we only support a single result value, i.e. no tuples
// this map is indexed by fnc.id -> potentially partial interval bound of result
// and similar for the errors
resultRangeBounds: Map[Identifier, PartialInterval] = Map(),
resultErrorBounds: Map[Identifier, Rational] = Map()
//requiredOutputRanges: Map[Identifier, Map[Identifier, PartialInterval]] = Map(),
//requiredOutputErrors: Map[Identifier, Map[Identifier, Rational]] = Map()
specResultRangeBounds: Map[Identifier, PartialInterval] = Map(),
specResultErrorBounds: Map[Identifier, Rational] = Map(),
// the analysed/computed roundoff errors for each function
resultAbsoluteErrors: Map[Identifier, Rational] = Map(),
resultRealRanges: Map[Identifier, Interval] = Map(),
// a None value indicates no relative error could be computed
resultRelativeErrors: Map[Identifier, Option[Rational]] = Map(),
// intermediate ranges and errors, which are needed e.g. for fixed-point codegen
intermediateAbsErrors: Map[Identifier, Map[Expr, Rational]] = Map(),
// real-valued ranges
intermediateRanges: Map[Identifier, Map[Expr, Interval]] = Map()
) {
// on the first creation of a context, we also update the context variable
......
/*
The contents of this file is heaviy influenced and/or partly taken from
the Leon Project which is released under the BSD 2 clauses license.
See file LEON_LICENSE or go to https://github.com/epfl-lara/leon
for full license details.
*/
package daisy
case class DaisyFatalError(msg: Option[String]) extends Exception(msg.getOrElse(""))
object DaisyFatalError {
def apply(msg: String) = new DaisyFatalError(Some(msg))
}
/*
The contents of this file is heaviy influenced and/or partly taken from
the Leon Project which is released under the BSD 2 clauses license.
See file LEON_LICENSE or go to https://github.com/epfl-lara/leon
for full license details.
*/
// Original work Copyright 2009-2016 EPFL, Lausanne
// Modified work Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
......@@ -14,6 +9,4 @@ import lang.Trees.Program
/** One logical analysis/synthesis step, e.g. computing ranges, replacing trig functions.
* This should be as immutable as possible so that we can (possibly) run it in parallel.
*/
trait DaisyPhase extends Pipeline[Program, Program] with Component {
}
trait DaisyPhase extends Pipeline[Program, Program] with Component
\ No newline at end of file
/*
The contents of this file is heaviy influenced and/or partly taken from
the Leon Project which is released under the BSD 2 clauses license.
See file LEON_LICENSE or go to https://github.com/epfl-lara/leon
for full license details.
*/
// Original work Copyright 2009-2016 EPFL, Lausanne
// Modified work Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
......@@ -14,7 +9,7 @@ import lang.Trees.Program
object Main {
val optionFunctions = ListOptionDef("functions", "Which functions to consider (currently only for error analysis).",
List("f1", "f2"))
List("f1", "f2"))
val optionPrintToughSMTCalls = FlagOptionDef("print-tough-smt-calls",
"If enabled, will print those SMT queries to file which take longer.")
......@@ -27,8 +22,8 @@ object Main {
FlagOptionDef("dynamic", "Run dynamic analysis."),
FlagOptionDef("relative", "Run experimental relative phase"),
FlagOptionDef("taylor", "Run experimental taylor simplification phase"),
FlagOptionDef("relabs", "Run experimental relative through absolute error phase"),
//ParamOptionDef("timeout", "Timeout in ms.", "1000"),
FlagOptionDef("absSubdiv", "Run experimental relative through absolute error phase"),
// ParamOptionDef("timeout", "Timeout in ms.", "1000"),
ListOptionDef("debug", "For which sections to print debug info.",
List("analysis","solver")),
FlagOptionDef("codegen", "Generate code (as opposed to just doing analysis)."),
......@@ -41,7 +36,7 @@ object Main {
For now these are phases, but it should be anything that
needs command-line options.
*/
lazy val allComponents : Set[DaisyPhase] = Set(
lazy val allComponents: Set[DaisyPhase] = Set(
analysis.SpecsProcessingPhase,
analysis.RangeErrorPhase,
analysis.RelativeErrorPhase,
......@@ -50,9 +45,9 @@ object Main {
backend.CodeGenerationPhase,
transform.SSATransformerPhase,
analysis.DynamicPhase,
InfoPhase)
backend.InfoPhase)
def main(args: Array[String]) {
def main(args: Array[String]): Unit = {
val ctx = processOptions(args.toList)
......@@ -62,7 +57,7 @@ object Main {
val timerTotal = ctx.timers.total.start
// this is the old frontend going through Leon
//val inputPrg = frontend.ScalaExtraction.run(ctx)
// val inputPrg = frontend.ScalaExtraction.run(ctx)
// new frontend going directly through Scala compiler
val inputPrg = frontend.ExtractionPhase(ctx)
......@@ -100,7 +95,7 @@ object Main {
opt.drop(2).split("=", 2).toList match {
case List(name, value) =>
allOptions.get(name) match {
case Some(ints: ParamOptionDef) => //if (value.forall(_.isDigit))
case Some(ints: ParamOptionDef) =>
validOptions +:= ParamOption(name, value)
case Some(lists: ListOptionDef) =>
......@@ -137,7 +132,8 @@ object Main {
case Some(rs) =>
debugSections += rs
case None =>
initReporter.error("Section "+ x +" not found, available: "+DebugSections.all.map(_.name).mkString(", "))
initReporter.error("Section " + x + " not found, available: " +
DebugSections.all.map(_.name).mkString(", "))
}
}}
......@@ -153,7 +149,7 @@ object Main {
)
}
private def showHelp(reporter: Reporter) {
private def showHelp(reporter: Reporter): Unit = {
reporter.info("usage: [--help] [--debug=<N>] [..] <files>")
reporter.info("")
for (opt <- globalOptions.toSeq.sortBy(_.name)) {
......@@ -188,12 +184,12 @@ object Main {
analysis.SpecsProcessingPhase andThen
transform.SSATransformerPhase andThen
analysis.RangeErrorPhase andThen
InfoPhase andThen
backend.InfoPhase andThen
backend.CodeGenerationPhase
} else if (ctx.hasFlag("codegen")) {
analysis.SpecsProcessingPhase andThen
analysis.RangeErrorPhase andThen
InfoPhase andThen
backend.InfoPhase andThen
backend.CodeGenerationPhase
} else if (ctx.hasFlag("relative")) {
analysis.SpecsProcessingPhase andThen
......@@ -201,14 +197,15 @@ object Main {
} else if (ctx.hasFlag("taylor")) {
analysis.SpecsProcessingPhase andThen
analysis.TaylorErrorPhase andThen
InfoPhase
} else if (ctx.hasFlag("relabs")) {
backend.InfoPhase
} else if (ctx.hasFlag("absSubdiv")) {
analysis.SpecsProcessingPhase andThen
analysis.RelThroughAbsPhase
analysis.RelThroughAbsPhase andThen
backend.InfoPhase
} else {
analysis.SpecsProcessingPhase andThen
analysis.RangeErrorPhase andThen
InfoPhase
backend.InfoPhase
}
}
......
/*
The contents of this file is heaviy influenced and/or partly taken from
the Leon Project which is released under the BSD 2 clauses license.
See file LEON_LICENSE or go to https://github.com/epfl-lara/leon
for full license details.
*/
// Original work Copyright 2009-2016 EPFL, Lausanne
// Modified work Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
......@@ -22,11 +17,11 @@ abstract class Reporter(val debugSections: Set[DebugSection]) {
case class Message(severity: Severity, position: Position, msg: Any)
private var _errorCount : Int = 0
private var _warningCount : Int = 0
private var _errorCount: Int = 0
private var _warningCount: Int = 0
final def errorCount : Int = _errorCount
final def warningCount : Int = _warningCount
final def errorCount: Int = _errorCount
final def warningCount: Int = _warningCount
def account(msg: Message): Message = {
msg.severity match {
......@@ -44,28 +39,29 @@ abstract class Reporter(val debugSections: Set[DebugSection]) {
throw DaisyFatalError(None)
}
def onCompilerProgress(current: Int, total: Int) = {}
def onCompilerProgress(current: Int, total: Int): Unit = {}
final def info(pos: Position, msg: Any): Unit = emit(account(Message(INFO, pos, msg)))
final def warning(pos: Position, msg: Any): Unit = emit(account(Message(WARNING, pos, msg)))
final def error(pos: Position, msg: Any): Unit = emit(account(Message(ERROR, pos, msg)))
final def title(pos: Position, msg: Any): Unit = emit(account(Message(INFO, pos, Console.BOLD + msg + Console.RESET)))
final def title(pos: Position, msg: Any): Unit = emit(account(Message(INFO, pos,
Console.BOLD + msg + Console.RESET)))
final def fatalError(pos: Position, msg: Any): Nothing = {
emit(account(Message(FATAL, pos, msg)))
onFatal()
}
final def internalError(pos: Position, msg : Any) : Nothing = {
final def internalError(pos: Position, msg: Any): Nothing = {
emit(account(Message(INTERNAL, pos, msg.toString +
"\nPlease inform the authors of Daisy about this message"
)))
onFatal()
}
final def internalAssertion(cond : Boolean, pos: Position, msg : Any) : Unit = {
final def internalAssertion(cond: Boolean, pos: Position, msg: Any): Unit = {
if (!cond) internalError(pos,msg)
}
def terminateIfError() = {
def terminateIfError(): Unit = {
if (errorCount > 0) {
_errorCount = 0
_warningCount = 0
......@@ -80,15 +76,15 @@ abstract class Reporter(val debugSections: Set[DebugSection]) {
(debugMask & section.mask) == section.mask
}
def ifDebug(pos: Position, body: (Any => Unit) => Any)(implicit section: DebugSection) = {
def ifDebug(pos: Position, body: (Any => Unit) => Any)(implicit section: DebugSection): Unit = {
if (isDebugEnabled) {
body( { (msg: Any) => emit(account(Message(DEBUG(section), pos, msg))) } )
body({ (msg: Any) => emit(account(Message(DEBUG(section), pos, msg))) })
}
}
def whenDebug(pos: Position, section: DebugSection)(body: (Any => Unit) => Any) {
def whenDebug(pos: Position, section: DebugSection)(body: (Any => Unit) => Any): Unit = {
if (isDebugEnabled(section)) {
body( { (msg: Any) => emit(account(Message(DEBUG(section), pos, msg))) } )
body({ (msg: Any) => emit(account(Message(DEBUG(section), pos, msg))) })
}
}
......@@ -106,8 +102,8 @@ abstract class Reporter(val debugSections: Set[DebugSection]) {
final def error(msg: Any): Unit = error(NoPosition, msg)
final def title(msg: Any): Unit = title(NoPosition, msg)
final def fatalError(msg: Any): Nothing = fatalError(NoPosition, msg)
final def internalError(msg: Any) : Nothing = internalError(NoPosition, msg)
final def internalAssertion(cond : Boolean, msg: Any) : Unit = internalAssertion(cond,NoPosition, msg)
final def internalError(msg: Any): Nothing = internalError(NoPosition, msg)
final def internalAssertion(cond: Boolean, msg: Any): Unit = internalAssertion(cond,NoPosition, msg)
final def debug(msg: => Any)(implicit section: DebugSection): Unit = debug(NoPosition, msg)
final def ifDebug(body: (Any => Unit) => Any)(implicit section: DebugSection): Unit =
ifDebug(NoPosition, body)
......@@ -117,12 +113,12 @@ abstract class Reporter(val debugSections: Set[DebugSection]) {
class DefaultReporter(debugSections: Set[DebugSection]) extends Reporter(debugSections) {
protected def severityToPrefix(sev: Severity): String = sev match {
case ERROR => "["+Console.RED +" Error "+Console.RESET+"]"
case WARNING => "["+Console.YELLOW +"Warning "+Console.RESET+"]"
case INFO => "["+Console.BLUE +" Info "+Console.RESET+"]"
case FATAL => "["+Console.RED+Console.BOLD +" Fatal "+Console.RESET+"]"
case INTERNAL => "["+ Console.BOLD +"Internal"+Console.RESET+"]"
case DEBUG(_) => "["+Console.MAGENTA +" Debug "+Console.RESET+"]"
case ERROR => "[" + Console.RED + " Error " + Console.RESET + "]"
case WARNING => "[" + Console.YELLOW + "Warning " + Console.RESET + "]"
case INFO => "[" + Console.BLUE + " Info " + Console.RESET + "]"
case FATAL => "[" + Console.RED + Console.BOLD + " Fatal " + Console.RESET + "]"
case INTERNAL => "[" + Console.BOLD + "Internal" + Console.RESET + "]"
case DEBUG(_) => "[" + Console.MAGENTA + " Debug " + Console.RESET + "]"
}
def smartPos(p: Position): String = {
......@@ -133,13 +129,13 @@ class DefaultReporter(debugSections: Set[DebugSection]) extends Reporter(debugSe
val here = new java.io.File(".").getAbsolutePath().stripSuffix(".")
val diff = target.stripPrefix(here)
val filePos = diff+":"
val filePos = diff + ":"
filePos + p + ": "
}
}
def emit(msg: Message) = {
def emit(msg: Message): Unit = {
println(reline(severityToPrefix(msg.severity), smartPos(msg.position) + msg.msg.toString))
printLineContent(msg.position)
}
......@@ -175,7 +171,7 @@ class DefaultReporter(debugSections: Set[DebugSection]) extends Reporter(debugSe
def printLineContent(pos: Position): Unit = {
getLine(pos) match {
case Some(line) =>
println(blankPrefix+line)
println(blankPrefix + line)
pos match {
case rp: RangePosition =>
val bp = rp.focusBegin
......@@ -185,21 +181,21 @@ class DefaultReporter(debugSections: Set[DebugSection]) extends Reporter(debugSe
val width = Math.max(ep.col - bp.col, 1)
"^" * width
} else {
val width = Math.max(line.length+1-bp.col, 1)
("^" * width)+"..."
val width = Math.max(line.length + 1 - bp.col, 1)
("^" * width) + "..."
}
println(blankPrefix+(" " * (bp.col - 1) + Console.RED+carret+Console.RESET))
println(blankPrefix + (" " * (bp.col - 1) + Console.RED + carret + Console.RESET))
case op: OffsetPosition =>
println(blankPrefix+(" " * (op.col - 1) + Console.RED+"^"+Console.RESET))
println(blankPrefix + (" " * (op.col - 1) + Console.RED + "^" + Console.RESET))
}
case None =>
}
}
protected def reline(pfx: String, msg: String) : String = {
pfx+" "+msg.replaceAll("\n", s"\n$pfx ")
protected def reline(pfx: String, msg: String): String = {
pfx + " " + msg.replaceAll("\n", s"\n$pfx ")
}
}
......
// Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
package analysis
......@@ -6,7 +8,7 @@ import java.io.BufferedWriter
import scala.util.Random
import lang.Trees._
import utils.{Rational, Interval, MPFRFloat}
import tools.{Rational, Interval, MPFRFloat}
import MPFRFloat.{abs => mpfr_abs, max => mpfr_max, min => mpfr_min}
import Rational._
import lang.Identifiers._
......@@ -110,7 +112,7 @@ object DynamicPhase extends DaisyPhase {
reporter.info("evaluating " + id + "...")
reporter.info(s"expression is $body")
val inputRanges: Map[Identifier, Interval] = ctx.inputRanges(id).map({
val inputRanges: Map[Identifier, Interval] = ctx.specInputRanges(id).map({
case (id, i) =>
(id, Interval(i.mid - inputRangeFactor * i.radius,
i.mid + inputRangeFactor * i.radius))
......
// Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
package analysis
import utils.{MPFRFloat, Rational}
import tools.{MPFRFloat, Rational}
import MPFRFloat.{abs => mpfr_abs, max => mpfr_max, min => mpfr_min}
import Rational.{abs => rat_abs, max => rat_max, min => rat_min}
import daisy.lang.Identifiers.Identifier
......
// Copyright 2017 MPI-SWS, Saarbruecken, Germany
package daisy
package analysis
import lang.NumAnnotation
import lang.Trees._
import utils._
import lang.TreeOps.allVariablesOf
import lang.Identifiers._
import tools._
import FinitePrecision._
import Rational._
import lang.Identifiers._
/**
??? Description goes here
Computes and stores intermediate ranges.
Prerequisites:
- SpecsProcessingPhase
*/
object RangeErrorPhase extends DaisyPhase with ErrorFunctions {
object RangeErrorPhase extends DaisyPhase with RoundoffEvaluators with IntervalSubdivision {
override val name = "range-error phase"
override val description = "Computes ranges and absolute errors"
val optionPrecision = ChoiceOptionDef("precision", "Type of precision to use",
Set("Float32", "Float64", "DoubleDouble", "QuadDouble",
"Fixed16", "Fixed32"), "Float64")
Set("Float32", "Float64", "DoubleDouble", "QuadDouble",
"Fixed16", "Fixed32"), "Float64")
override val definedOptions: Set[CmdLineOptionDef[Any]] = Set(
ChoiceOptionDef("rangeMethod", "Method to use for range analysis",
......@@ -37,10 +40,6 @@ object RangeErrorPhase extends DaisyPhase with ErrorFunctions {
var reporter: Reporter = null
// Var for error functions
// trackRoundoffErrs and uniformPrecision assigned below in run
attachToTree = true
override def run(ctx: Context, prg: Program): (Context, Program) = {
reporter = ctx.reporter
reporter.info(s"\nStarting $name")
......@@ -51,9 +50,8 @@ object RangeErrorPhase extends DaisyPhase with ErrorFunctions {
var errorMethod = "affine" // only one supported so far
var trackInitialErrs = true
var trackRoundoffErrs = true