
- Scala - Home
- Scala - Overview
- Scala - Features
- Scala - Environment Setup
- Scala - Build Tool (SBT)
- Scala - REPL
- Scala - Dot & Dotty
- Scala - Basic Syntax
- Scala - Hello World Program
- Scala - Identifiers
- Scala - Keywords
- Scala - Comments
- Scala - Code Blocks
- Scala - Semicolon
- Scala - Constructs
- Scala - Expressions
- Scala - Input and Output
- Scala - Optional Braces
- Scala - Underscore (_)
- Data Types and Variables
- Scala - Data Types
- Scala - Type Bounds
- Scala - Context Bound
- Scala - Variances
- Scala - Type Hierarchy
- Scala - Variables
- Scala - Variable Scopes
- Scala - Literals
- Scala - Numeric Types
- Scala - Boolean Types
- Scala - Char Type
- Scala - Unit Types
- Scala - Strings
- Scala - Arrays
- Scala - Null Type
- Scala - Nothing
- Scala - Any Type
- Scala - AnyRef Type
- Scala - Unified Types
- Scala - Dates and Times
- Scala - Ranges
- Scala - Multidimensional Arrays
- Scala - WrappedArray
- Scala - StringBuilder
- Scala - String Interpolation
- Scala - StringContext
- Scala - Type Casting
- Scala var vs val
- Scala Operators
- Scala - Operators
- Scala - Rules for Operators
- Scala - Arithmetic Operators
- Scala - Relational Operators
- Scala - Logical Operators
- Scala - Bitwise Operators
- Scala - Assignment Operators
- Scala - Operators Precedence
- Scala - Symbolic Operators
- Scala - Range Operator
- Scala - String Concatenation Operator
- Scala Conditional Statements
- Scala - IF ELSE
- Scala - IF-ELSE-IF-ELSE Statement
- Scala - Nested IF-ELSE Statement
- Scala Loop Statements
- Scala - Loop Statements
- Scala - while Loop
- Scala - do-while Loop
- Scala - Nested Loops
- Scala - for Loop
- Scala - break Statement
- Scala - yield Keyword
- Scala Classes & Objects
- Scala - Classes & Objects
- Scala - Constructors
- Scala - Auxiliary Constructor
- Scala - Primary Constructor
- Scala - This Keyword
- Scala - Nested Classes
- Scala - Getters and Setters
- Scala - Object Private Fields
- Scala - Singleton Object
- Scala - Companion Objects
- Scala - Creating Executable Programs
- Scala - Stateful Object
- Scala - Enumerations
- Scala - Polymorphism
- Scala - Access Modifiers
- Scala - Apply Method
- Scala - Update Methods
- Scala - UnapplySeq Method
- Scala - Inheritance
- Scala - Extending a Class
- Scala - Method Overloading
- Scala - Method Overriding
- Scala - Generic Classes
- Scala - Generic Functions
- Scala - Superclass Construction
- Scala Methods & Functions
- Scala - Functions
- Scala - Main Methods
- Scala - Functions Call-by-Name
- Scala - Functions with Named Arguments
- Scala - Function with Variable Arguments
- Scala - Recursion Functions
- Scala - Default Parameter Values
- Scala - Functions without Parameters
- Scala - Implicit Parameters
- Scala - Higher-Order Functions
- Scala - Nested Functions
- Scala - Extension Methods
- Scala - Anonymous Functions
- Partially Applied Functions
- Scala - Lazy Val
- Scala - Pure Function
- Scala - Currying Functions
- Scala - Control Abstractions
- Scala - Corecursion
- Scala - Unfold
- Scala - Tail Recursion
- Scala - Infinite Sequences
- Scala - Dynamic Invocation
- Scala - Lambda Expressions
- Scala Collections
- Scala - Collections
- Mutable and Immutable Collections
- Scala - Lists
- Scala - Sets
- Scala - Maps
- Scala - TreeMap
- Scala - SortedMap
- Scala - Tuples
- Scala - Iterators
- Scala - Options
- Scala - Infinite Streams
- Scala - Parallel Collections
- Scala - Algebraic Data Types
- Scala Pattern Matching
- Scala - Pattern Matching
- Scala - Type Patterns
- Scala - Exception Handling
- Scala - Extractors
- Scala - Regular Expressions
- Scala Files I/O
- Scala - Files I/O
- Scala Advanced Concepts
- Scala - Closures
- Scala - Futures
- Scala - Promises
- Scala - Traits
- Scala - Trait Mixins
- Scala - Layered Traits
- Scala - Trait Linearization
- Scala - Sealed Traits
- Scala - Transparent Traits
- Scala - Literal Type Arithmetic
- Scala - Inline keyword
- Scala - Def, Var & Val
- Scala - Dropped Features
- Scala - BDD Testing
Scala - Numeric Types
Scala numeric types provide basic understanding and managing numbers. It ensures accuracy in applications and improves coding. In this tutorial, we will understand about numeric types in Scala.
Basic of Scala Numeric Types
Scala provides various numeric types for computational needs. Developers can handle various formats and can ensure efficiency and precision in calculations. These numeric types are Integral types, Floating types. We will also discuss their Type ranges. We have discussed these in brief below.
1. Integral Types
In Scala, there are various types of Integral types to represent whole numbers. These integral types are Short, Int, Long and Byte. Each type has a specific range. For example,
val byteVal: Byte = 125 val shortVal: Short = 32767 val intVal: Int = 2135482547 val longVal: Long = 9223372036854775807L
2. Floating-Point Types
Scala has Float and Double for decimal numbers. You can choose based on precision needs. For example,
val floatVal: Float = 2.718F val doubleVal: Double = 2.718281828459045
3. Type Ranges
Integral types and Floating types have their specific ranges. So you can choose the right type for specific tasks. Here is brief of their ranges:
Type | Min Value | Max Value |
---|---|---|
Byte | -128 | 127 |
Short | -32768 | 32767 |
Int | -2147483648 | 2147483647 |
Long | -9223372036854775808 | 9223372036854775807 |
Numeric Types: Integers and Floating Points
In Scala, there are two types of numbers: Integers and Floating Points. These are basic types of numbers used for various mathematical calculations in Scala programs. These are important for simple arithmetic and complex algorithms.
1. Arithmetic Operations
You can perform arithmetic operations with Integers in a straightforward way. You need to use operators like, *,/,+,- etc. For example,
val difference: Int = 8 - 3 val quotient: Int = 15 / 3 val sum: Int = 5 + 3 val product: Int = 5 * 3 val power: Int = 2 ^ 3
For Floating Point numbers the result can be different but operators are always the same. For example,
val difference: Float = 8.0f - 3.0f val quotient: Float = 15.0f / 3.0f val sum: Float = 5.0f + 3.0f val product: Float = 5.0f * 3.0f val power: Float = math.pow(2.0, 3.0).toFloat
2. Type Casting
You may require conversion from Integers to Floating Point numbers and vice-versa. So you can use Type Casting for these conversions. In Scala, methods like toFloat and toInt are used here. For example,
val integerValue: Int = 10 val doubleValue: Double = integerValue.toDouble
And conversely,
val floatValue: Float = 7.5f val integerValue: Int = floatValue.toInt
Numeric Types - Comparisons and Equality
Sometimes, you need to compare integers and floating points. You can do this using standard comparison symbols like ==, !=, <, >, <=, and >=. For example,
val isNotEqual: Boolean = 8 != 3 val isLessOrEqual: Boolean = 2.0 <= 2.5
While comparing floating points, you need to be careful about precision problems. Tiny rounding errors can cause surprising outcomes. It is better to see if two floating points are 'close enough' instead of precisely equal.
Precision and Limitations
Precision and inherent limitations of numeric types are important. Scala has defined boundaries and behaviors for its numeric types that developers need to know about.
1. Floating-Point Precision
In Scala, Floating Point numbers are represented by Float and Double. These two have inherent and precision limitations. You can store decimal values but they might not always be stored accurately. For example,
val sumResult: Double = 1.5 + 2.7 println(sumResult) // Might not be exactly 4.2 due to precision issues
2. Integer Overflow
In Scala, Integers are fixed size. Because of fixed size, these can have underflow and overflow scenarios. When an integer exceeds its minimum value then it wraps to maximum value and vice-versa. For example,
val minInt: Int = Int.MinValue val underflowed: Int = minInt - 1
3. Rounding Errors
Dealing with floating-point numbers can be tricky due to rounding errors. These errors occur because binary systems may not always perfectly represent certain decimal fractions. For example,
val roundedValue: Double = Math.round(0.785 * 100) / 100.0 println(roundedValue) // Might not be exactly 0.79 due to rounding errors
4. Safe Operations
To avoid problems with precision, especially when working with floating points, you can use libraries for arbitrary precision arithmetic. These tools can give you accurate results.
Type Conversion and Casting Between Numeric Types
In Scala, you may need data conversion, i.e., convert one data type into another type. This process is known as Casting. It is used to reduce error while representing floating-point format.
1. Implicit and Explicit Conversion
Scala has both Explicit and Implicit type conversion. Implicit occurs automatically when context requires it. Whereas, developers can do explicit conversion when required. For example,
val floatValue: Float = 7.5f val intValue: Int = floatValue.toInt // Implicit conversion
And explicit conversion:
val floatVal2: Float = 3.14f val intVal2: Int = floatVal2.toInt // Explicit conversion
There is a chance for losing data when you cast from larger one to smaller one. For example,
val largeFloat: Float = 1.5e7f val castedInt: Int = largeFloat.toInt // Potential data loss
You should be aware about it before conversion and handle such errors. In Scala, there is a hierarchy for Numeric types. This hierarchy is given as follows below.
Type | Can widen to |
---|---|
Byte | Short, Int, Long, Float, Double |
Short | Int, Long, Float, Double |
Int | Long, Float, Double |
Long | Float, Double |
2. Generic Numeric Operations
In Scala, Numeric types provide versatility and precision. You can create generic functions that operate on any numeric types. For example, if you require a function to work with any numeric type. Like this Haskell approach:
case class NumericPair[A](first: A, second: A)(implicit num: Numeric[A])
You can perform various operations like subtraction, addition, multiplication and division using Numeric[A] traits. It is not extended by basic types like Float and Int. It provides implicit objects. For example, num.plus(a, b) instead of a+b.
3. Custom Numeric Types
Sometimes, inbuilt numeric types don't meet your needs. For example, if you want to define a custom Decimal type for accurate calculations. Though you can not extend the Numeric trait directly. But you can create an instance of this type.
final class CustomNumber(val value: Int) extends AnyVal object CustomNumber { implicit val numeric: Numeric[CustomNumber] = new Numeric[CustomNumber] { // Define operations like plus, minus, times, etc. } }
4. Vector operations with Numeric Types
Vector is a data structure used in many applications, like physics and graphics simulations. While creating a generic Vector class in Scala, you may require it compatible with all numeric types.
class Point2D[@specialized T](val x: T, val y: T)(implicit num: Numeric[T]) { def +(other: Point2D[T]) = new Point2D(num.plus(x, other.x), num.plus(y, other.y)) }
This approach involves using the `@specialized` annotation to optimize for specific types. It ensures efficient operations without the overhead of boxing.
5. Safe Division and Handling
You can handle division by zero using the Option type. For example,
def safeDivision(dividend: Int, divisor: Int): Option[Int] = if (divisor == 0) None else Some(dividend / divisor) You need to use `map` function for the result: safeDivision(6, 2).map(_ * 6) // Returns Option[Int] with value Some(18)
Optimizing Performance with Numeric Types
You can optimize Scala programs with the help of Numeric types.
Specialized Annotations
When specialized Annotations are used in the Scala program, then the compiler generates optimized bytecode and reduces overhead unboxing and boxing operations. For example,
def multiply[@specialized(Int, Double) T](a: T, b: T)(implicit numeric: Numeric[T]): T = numeric.times(a, b)
Boxing and Unboxing are processes which have wrapping (boxing) primitive types into their object counterparts and vice versa. It can have performance overhead. You can use value classes to avoid this overhead. For example,
final class EnhancedDouble(val value: Double) extends AnyVal { def cube: Double = value * value * value }
There will not be any object overhead because of AnyVal extension.
Note that there are BigInt and BigDecimal in scala for large number operations. But these are immutable and can be slower than primitive types.