01 Overview
This lesson continues the technical art C# data types lesson 2, focusing on practical usage of variables and operations in production code.
Unsigned wraparound. uint and ulong can never go negative — subtracting past zero wraps to a huge positive number instead of throwing. A countdown loop like for (uint i = 10; i >= 0; i--) never terminates. When a value might subtract or count down, use a signed type (int/long) instead.
uint — unsigned 32-bit integer
Beginner explanation: Like int, but only positive numbers (0 to 4.3 billion). Perfect for bit operations, color values (RGBA), large positive numbers, hash codes, or anything that should never be negative. Double the positive range of int!
Technical specs
- Size: 4 bytes (32 bits)
- Range: 0 to 4,294,967,295 (~4.3 billion)
- Signed: No (unsigned - positive only)
- Default Value: 0
Performance notes
- Same speed as int (32-bit optimized)
- Double positive range vs int
- Perfect for bit operations (no sign bit)
- DANGER: Subtraction wrapping is a common source of bugs
- Use for: bit flags, colors, hashes, frame counters
Avoid for: anything involving subtraction or comparisons with negative values
When to use uint
- Bit masks and flags (32 boolean values in one variable)
- Packed color values (RGBA format)
- Hash codes and checksums
- Frame/tick counters (never negative)
- Large positive-only IDs
- Network packet data
- Don't use for loops that count down
- Don't use if you ever subtract or compare with negatives
- Don't use just because "it's never negative" - int is safer!
Syntax and declaration
// Basic declaration (note 'u' suffix for literals)
uint colorRGBA = 0xFF5733FF; // Color in hex (RGBA format)
uint hash = 0xABCDEF12; // Hash value
uint largeCount = 3000000000; // Large positive number
// The 'u' suffix tells compiler it's uint (optional but recommended)
uint explicitUInt = 100u; // With 'u' suffix
uint implicitUInt = 100; // Without suffix (also works)
// Practical examples
uint objectID = 2000000000; // Large object ID
uint bitMask = 0b11110000; // Bit mask (binary notation)
uint flags = 0; // Flag storage (32 boolean flags)
Practical use cases
// Color operations (packed RGBA format)
uint packedColor = 0xFF0080FF; // R=255, G=0, B=128, A=255
// Extract color components (bit shifting)
byte r = (byte)((packedColor >> 24) & 0xFF); // Red channel
byte g = (byte)((packedColor >> 16) & 0xFF); // Green channel
byte b = (byte)((packedColor >> 8) & 0xFF); // Blue channel
byte a = (byte)(packedColor & 0xFF); // Alpha channel
// Pack color from components
uint PackColor(byte r, byte g, byte b, byte a)
{
return ((uint)r << 24) | ((uint)g << 16) | ((uint)b << 8) | a;
}
// Game entity IDs (for large games)
uint entityID = 1000000; // Entity unique ID
uint playerID = 500000; // Player identifier
uint worldObjectID = 2500000; // World object ID
// Bit flags (store 32 boolean values in one uint!)
uint playerFlags = 0;
uint FLAG_ALIVE = 1u << 0; // Bit 0: Is alive
uint FLAG_MOVING = 1u << 1; // Bit 1: Is moving
uint FLAG_JUMPING = 1u << 2; // Bit 2: Is jumping
uint FLAG_CROUCHING = 1u << 3; // Bit 3: Is crouching
uint FLAG_SPRINTING = 1u << 4; // Bit 4: Is sprinting
// Set flags
playerFlags |= FLAG_ALIVE; // Turn on "alive" flag
playerFlags |= FLAG_MOVING; // Turn on "moving" flag
// Clear flags
playerFlags &= ~FLAG_JUMPING; // Turn off "jumping" flag
// Check flags
bool isAlive = (playerFlags & FLAG_ALIVE) != 0;
bool isMoving = (playerFlags & FLAG_MOVING) != 0;
// Frame/Tick counters (wraps after ~2 years at 60fps)
uint frameCount = 0;
void Update()
{
frameCount++; // Will overflow after 4,294,967,295 frames
// At 60 fps: ~828 days, at 120 fps: ~414 days
}
// Network/Protocol
uint networkPacketID = 50000; // Packet counter
uint sequenceNumber = 0; // Sequence tracking
uint timestamp = 1699999999; // Unix timestamp (seconds)
// Hash codes
uint stringHash = 0;
uint GetHashCode(string text)
{
uint hash = 0;
foreach (char c in text)
{
hash = hash * 31 + c;
}
return hash;
}
// Random number generator seeds
uint randomSeed = 12345u;
System.Random random = new System.Random((int)randomSeed);
// Bit manipulation examples
uint value = 0b10101010; // Binary: 10101010
uint shifted = value << 2; // Shift left 2 bits: 1010101000
uint masked = value & 0x0F; // Keep only lower 4 bits
uint combined = value | 0xF0; // Set upper 4 bits
Common pitfalls
// PITFALL 1: Subtraction wraps around (MOST COMMON BUG!)
uint a = 10u;
uint b = 20u;
uint result = a - b; // Result = 4,294,967,286 (NOT -10!)
// This is EXTREMELY dangerous and hard to debug!
// Fix: Check before subtracting OR use int for calculations
if (a > b)
{
uint diff = a - b; // Safe
}
else
{
// Handle case where a < b
}
// Better: Use int if you need negatives
int safeDiff = (int)a - (int)b; // -10 (correct)
// PITFALL 2: Countdown loops (INFINITE LOOP!)
for (uint i = 10u; i >= 0; i--) // NEVER TERMINATES!
{
// When i reaches 0, i-- wraps to 4,294,967,295!
// Loop continues forever!
}
// Fix: Use int for countdown loops
for (int i = 10; i >= 0; i--) // Works correctly
{
// Terminates properly
}
// PITFALL 3: Comparing with signed integers
uint unsigned = 10u;
int signed = -5;
if (unsigned > signed) // TRUE, but DANGEROUS!
{
// signed (-5) becomes 4,294,967,291 when converted to uint!
// This comparison is misleading!
}
// Fix: Be explicit about conversions
if ((int)unsigned > signed) // Safe comparison
{
// Both are int now
}
// PITFALL 4: Overflow at 4.3 billion
uint max = 4294967295u; // Max value
max += 1u; // Wraps to 0!
// Fix: Check before incrementing
if (max < uint.MaxValue)
{
max++;
}
// PITFALL 5: Implicit conversion issues
uint value = 100u;
int negative = -50;
uint result = value + negative; // Error! Can't add int to uint implicitly
// Fix: Cast explicitly (but be careful!)
uint result = value + (uint)negative; // -50 becomes 4,294,967,246!
// PITFALL 6: Division by zero still possible
uint a = 10u;
uint b = 0u;
uint result = a / b; // Runtime error: DivideByZeroException
// Always check
if (b != 0)
{
uint result = a / b;
}
// PITFALL 7: Mixing with float/double
uint bigNum = 4000000000u;
float result = bigNum; // Precision loss! float can't represent all uint values accurately
Pro tips
// TIP 1: Perfect for bit flags (32 booleans in 4 bytes!)
[System.Flags]
enum GameState : uint
{
None = 0,
Paused = 1 << 0, // Bit 0
GameOver = 1 << 1, // Bit 1
Loading = 1 << 2, // Bit 2
Cutscene = 1 << 3, // Bit 3
// ... up to 32 flags
}
uint state = 0;
state |= (uint)GameState.Paused; // Set flag
bool isPaused = (state & (uint)GameState.Paused) != 0; // Check flag
// TIP 2: Packed color helpers
struct ColorRGBA
{
private uint packed;
public ColorRGBA(byte r, byte g, byte b, byte a)
{
packed = ((uint)r << 24) | ((uint)g << 16) | ((uint)b << 8) | a;
}
public byte R => (byte)(packed >> 24);
public byte G => (byte)(packed >> 16);
public byte B => (byte)(packed >> 8);
public byte A => (byte)packed;
public uint Packed => packed;
}
// TIP 3: Use for hash functions
uint SimpleHash(string text)
{
uint hash = 0;
foreach (char c in text)
{
hash = (hash << 5) - hash + c; // hash * 31 + c
}
return hash;
}
// TIP 4: Frame counter with wrapping awareness
uint frameCount = 0;
uint lastCheckFrame = 0;
void Update()
{
frameCount++;
// Calculate frame difference (handles wrapping!)
uint frameDelta = frameCount - lastCheckFrame;
if (frameDelta >= 60) // Every 60 frames
{
DoSomething();
lastCheckFrame = frameCount;
}
}
// TIP 5: Network sequence numbers
uint sequenceNumber = 0;
uint GetNextSequence()
{
return sequenceNumber++; // Auto-wraps at 4.3 billion
}
bool IsSequenceNewer(uint current, uint received)
{
// Handle wrapping: if difference is huge, it wrapped
return (received > current) && ((received - current) < 0x80000000);
}
// TIP 6: ALWAYS use int for countdown loops!
// WRONG:
for (uint i = 10; i >= 0; i--) // Infinite loop!
// CORRECT:
for (int i = 10; i >= 0; i--) // Works properly
// TIP 7: Clamp helper
uint ClampUInt(long value)
{
if (value < 0) return 0;
if (value > uint.MaxValue) return uint.MaxValue;
return (uint)value;
}
// TIP 8: Check for wraparound in subtraction
uint SafeSubtract(uint a, uint b)
{
if (a >= b)
return a - b;
else
return 0; // Return 0 instead of wrapping
}
// TIP 9: Use for bitmask operations
uint CREATE_MASK(int bitCount)
{
return (1u << bitCount) - 1; // Creates mask of N bits
}
uint mask4Bits = CREATE_MASK(4); // 0b00001111 (15)
uint mask8Bits = CREATE_MASK(8); // 0b11111111 (255)
// TIP 10: Layer masks in Unity
uint layerMask = 1u << LayerMask.NameToLayer("Enemy"); // Single layer
uint multiLayer = (1u << 8) | (1u << 9); // Multiple layers (8 and 9)
long — large numbers and timestamps
Beginner explanation: A very big box for very big numbers! Can store from -9 quintillion to +9 quintillion. Use for timestamps (milliseconds since 1970), file sizes (gigabytes), large calculations, database IDs, or when int isn't big enough. Takes double the memory of int, but you get HUGE range.
Technical specs
- Size: 8 bytes (64 bits)
- Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (~±9.2 quintillion)
- Signed: Yes (can be negative)
- Default Value: 0
Performance notes
- Fast on 64-bit systems (native register size)
- Slightly slower on 32-bit systems (requires two operations)
- Same speed as int on modern 64-bit CPUs
- No conversion overhead when working with time APIs
- Uses 2x memory of int (8 bytes vs 4 bytes)
- Use when: int range isn't enough OR working with timestamps/file sizes
When to use long
- Timestamps (milliseconds since Unix epoch)
- File sizes (especially > 2GB)
- Database IDs (primary keys)
- High-precision timers
- Large world coordinates (space games)
- When calculations might exceed ±2 billion
- Don't use by default (wastes memory)
- Don't use for small counters/IDs
Syntax and declaration
// Basic declaration (note the 'L' suffix!)
long timestamp = 1699999999999L; // Must use 'L' suffix!
long fileSize = 5368709120L; // 5 GB in bytes
long largeNumber = 9000000000L; // 9 billion
// Without 'L' suffix, compiler treats as int (ERROR if > 2 billion)
long wrong = 3000000000; // Error! Literal too large for int
long correct = 3000000000L; // Correct with 'L'
// Practical examples
long milliseconds = System.DateTime.Now.Ticks; // High-precision time
long databaseID = 123456789012345L; // Database primary key
long worldSeed = 987654321098L; // World generation seed
Practical use cases
// Timestamps (most common use!)
long unixTimeMs = DateTimeOffset.Now.ToUnixTimeMilliseconds(); // 1699999999999
long unixTimeSec = DateTimeOffset.Now.ToUnixTimeSeconds(); // 1699999999
long ticksNow = DateTime.Now.Ticks; // 638365440000000000 (ticks since year 1)
// Convert between timestamps
long millisecondsToTicks = milliseconds * TimeSpan.TicksPerMillisecond;
long ticksToMilliseconds = ticks / TimeSpan.TicksPerMillisecond;
// File operations
long fileSize = new FileInfo("large_file.bin").Length; // File size in bytes
long totalBytes = 5L * 1024L * 1024L * 1024L; // 5 GB
// File size formatting
string FormatFileSize(long bytes)
{
if (bytes < 1024) return $"{bytes} B";
if (bytes < 1024 * 1024) return $"{bytes / 1024.0:F2} KB";
if (bytes < 1024 * 1024 * 1024) return $"{bytes / (1024.0 * 1024):F2} MB";
return $"{bytes / (1024.0 * 1024 * 1024):F2} GB";
}
// Large world coordinates (space games, procedural generation)
long worldX = 1000000000L; // Far from origin
long worldY = -500000000L;
long worldZ = 2000000000L;
// Space game example
struct GalacticPosition
{
public long x; // Can represent entire galaxy
public long y;
public long z;
}
// Database/Network
long userID = 123456789012L; // User ID from database
long sessionID = 987654321098L; // Session identifier
long transactionID = 555666777888L; // Payment transaction
// Game development
long experiencePoints = 10000000000L; // Total XP earned
long goldEarned = 5000000000L; // Currency (if > 2 billion)
long frameTime = DateTime.Now.Ticks; // High-precision timer
long randomSeed = 192837465019L; // Procedural generation
// Physics/Simulation (high precision needed)
long nanoSeconds = 1000000000L; // 1 second in nanoseconds
long microSeconds = 1000000L; // 1 second in microseconds
// High-precision stopwatch
long startTicks = System.Diagnostics.Stopwatch.GetTimestamp();
// ... game logic ...
long endTicks = System.Diagnostics.Stopwatch.GetTimestamp();
long elapsedTicks = endTicks - startTicks;
double elapsedMs = (elapsedTicks * 1000.0) / System.Diagnostics.Stopwatch.Frequency;
// Particle/Entity counting (massive simulations)
long particleCount = 8000000000L; // 8 billion particles
long entityCount = 5000000000L; // 5 billion entities
Common pitfalls
// PITFALL 1: Forgetting the 'L' suffix
long big = 3000000000; // Compiler error! Treated as int
long big = 3000000000L; // Correct
// PITFALL 2: Implicit conversion from int to long (safe)
int smallValue = 100;
long bigValue = smallValue; // Automatic (safe - no data loss)
// But reverse is NOT automatic!
long bigValue = 1000L;
int smallValue = bigValue; // Error! Possible data loss
int smallValue = (int)bigValue; // Must cast explicitly
// PITFALL 3: Overflow still exists (but at much larger values)
long max = long.MaxValue; // 9,223,372,036,854,775,807
max += 1L; // Wraps to -9,223,372,036,854,775,808!
// Use checked context to catch overflow
checked
{
long result = long.MaxValue + 1L; // Throws OverflowException
}
// PITFALL 4: DateTime.Ticks vs Unix timestamp confusion
long ticks = DateTime.Now.Ticks; // 638365440000000000 (ticks since year 1)
long unix = DateTimeOffset.Now.ToUnixTimeSeconds(); // 1699999999 (seconds since 1970)
// These are DIFFERENT! Don't mix them up!
// Convert Unix to DateTime
DateTime dateFromUnix = DateTimeOffset.FromUnixTimeSeconds(unix).DateTime;
// PITFALL 5: Mixing long with float/double in calculations
long bigNum = 10000000000L;
float result = bigNum * 1.5f; // Precision loss! float can't represent all long values
double result = bigNum * 1.5; // Better, but still potential precision issues with VERY large longs
// PITFALL 6: File size overflow
int fileSize = (int)file.Length; // Files > 2GB will overflow!
long fileSize = file.Length; // Correct
// PITFALL 7: Integer division with longs
long a = 10L;
long b = 3L;
long result = a / b; // 3 (integer division!)
double accurate = (double)a / b; // 3.333... (need double for decimals)
Pro tips
// TIP 1: Use for Unix timestamps (milliseconds)
long GetCurrentTimeMs()
{
return DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
long GetCurrentTimeSec()
{
return DateTimeOffset.Now.ToUnixTimeSeconds();
}
// Convert timestamp to DateTime
DateTime ConvertUnixToDateTime(long unixTimeMs)
{
return DateTimeOffset.FromUnixTimeMilliseconds(unixTimeMs).DateTime;
}
// TIP 2: File size calculations
long KB = 1024L;
long MB = 1024L * 1024L;
long GB = 1024L * 1024L * 1024L;
long TB = GB * 1024L;
long fiveGB = 5L * GB; // 5 GB in bytes
// TIP 3: High-precision timers in games
class GameTimer
{
private long startTicks;
public void Start()
{
startTicks = System.Diagnostics.Stopwatch.GetTimestamp();
}
public double GetElapsedMilliseconds()
{
long currentTicks = System.Diagnostics.Stopwatch.GetTimestamp();
long elapsedTicks = currentTicks - startTicks;
return (elapsedTicks * 1000.0) / System.Diagnostics.Stopwatch.Frequency;
}
}
// TIP 4: Large world coordinates (open world games)
// Store as millimeters for precision in huge worlds
long worldX = (long)(playerPosition.x * 1000.0); // Convert meters to millimeters
long worldY = (long)(playerPosition.y * 1000.0);
// Convert back
float posX = worldX / 1000.0f; // Millimeters to meters
// TIP 5: Use const for large constant values
const long MAX_FILE_SIZE = 5L * 1024L * 1024L * 1024L; // 5 GB
const long TICKS_PER_SECOND = 10000000L; // DateTime ticks
const long MILLISECONDS_PER_DAY = 24L * 60L * 60L * 1000L;
// TIP 6: Check for overflow in critical code
checked
{
long result = value1 + value2; // Throws OverflowException if overflow
}
// Or check before operation
long SafeAdd(long a, long b)
{
if (a > 0 && b > long.MaxValue - a)
return long.MaxValue; // Would overflow
if (a < 0 && b < long.MinValue - a)
return long.MinValue; // Would underflow
return a + b;
}
// TIP 7: Convert between different time units
long seconds = 60L;
long milliseconds = seconds * 1000L;
long microseconds = milliseconds * 1000L;
long nanoseconds = microseconds * 1000L;
// Reverse
long msToSeconds = milliseconds / 1000L;
// TIP 8: DateTime operations
long GetDaysBetween(DateTime start, DateTime end)
{
long ticksDiff = end.Ticks - start.Ticks;
return ticksDiff / TimeSpan.TicksPerDay;
}
// TIP 9: Random seed generation
long GenerateRandomSeed()
{
return DateTime.Now.Ticks; // Use current time as seed
}
Random random = new Random((int)(DateTime.Now.Ticks & 0xFFFFFFFF)); // Use lower 32 bits
// TIP 10: Large array indices (rare but possible)
long hugeArrayIndex = 5000000000L; // Index beyond int.MaxValue
// Note: C# arrays still use int for indices, but can calculate with long
int safeIndex = (int)(hugeArrayIndex % array.Length); // Wrap to valid range
// TIP 11: Stopwatch for performance measurement
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// ... code to measure ...
stopwatch.Stop();
long elapsedMs = stopwatch.ElapsedMilliseconds; // Returns long
long elapsedTicks = stopwatch.ElapsedTicks; // Returns long
// TIP 12: Check if value fits in long
bool FitsInLong(decimal value)
{
return value >= long.MinValue && value <= long.MaxValue;
}
bool FitsInInt(long value)
{
return value >= int.MinValue && value <= int.MaxValue;
}
if (FitsInInt(longValue))
{
int intValue = (int)longValue;
}
ulong — unsigned 64-bit integer
Beginner explanation: The biggest box for positive numbers only! Can store 0 to 18.4 quintillion (18 followed by 18 zeros!). Use for extremely large positive values like file sizes, crypto operations, huge counters, or scientific calculations. Rarely needed in typical game development, but essential for specific cases.
Technical specs
- Size: 8 bytes (64 bits)
- Range: 0 to 18,446,744,073,709,551,615 (~18.4 quintillion)
- Signed: No (unsigned - positive only)
Default Value: 0
Performance notes
- Same speed as long on 64-bit systems
- Slower on 32-bit systems
- Double positive range vs long
- Subtraction wrapping is dangerous (like uint)
- Very rarely needed in game development
- Use only when: long range isn't enough AND values are positive-only
When to use ulong
- Extremely large file sizes (> 9 exabytes)
- Cryptographic operations (hashing, keys)
- Scientific calculations with huge positive values
- 64-bit hashing
- Blockchain/cryptocurrency data
- Astronomical calculations
- Almost never needed in typical games
- Don't use for countdown loops
- Don't use if long is sufficient
Syntax and declaration
// Basic declaration (note 'UL' or 'ul' suffix)
ulong hugeNumber = 15000000000000000000UL; // 15 quintillion
ulong fileSize = 10000000000UL; // 10 GB in bytes
ulong counter = 0UL;
// Practical examples
ulong totalBytes = 18446744073709551615UL; // Max value
ulong blockchainHash = 0xFFFFFFFFFFFFFFFFUL; // Crypto hash
ulong largeID = 999999999999999UL; // Very large identifier
Practical use cases
// File system (handles HUGE files > 16 exabytes)
ulong driveSize = GetDriveTotalSize(); // Total drive space
ulong freeSpace = GetDriveFreeSpace(); // Available space
ulong fileSize = GetFileSize("huge_file.bin");
// Helper functions
ulong GetDriveTotalSize(string drive)
{
DriveInfo info = new DriveInfo(drive);
return (ulong)info.TotalSize;
}
// Cryptocurrency/Blockchain
ulong satoshis = 100000000UL; // 1 Bitcoin = 100 million satoshis
ulong blockHeight = 750000UL; // Block number in blockchain
ulong transactionHash = 0x123456789ABCDEFFUL; // Transaction hash
// Cryptography
ulong hash64 = ComputeHash64(data); // 64-bit hash
ulong nonce = 0UL; // Mining nonce
// Game statistics (lifetime counters)
ulong totalDamageDealt = 0UL; // Lifetime damage counter
ulong totalGoldEarned = 0UL; // Lifetime currency earned
ulong totalStepsTaken = 0UL; // Total steps in game
ulong totalExperience = 0UL; // Total XP ever earned
// Procedural generation (huge seeds)
ulong universeID = 12345678901234UL; // Procedural universe ID
ulong galaxySeed = 98765432109876UL; // Galaxy generation seed
// Network/Data
ulong totalBytesReceived = 0UL; // Network statistics
ulong totalBytesSent = 0UL; // Upload statistics
ulong packetCount = 0UL; // Total packets processed
// Scientific/Astronomy
ulong atomCount = 6022140857000000000000000UL; // Avogadro's number approximation
ulong lightYearInMeters = 9460730472580800UL; // Light year distance
// Performance counters
ulong cpuCycles = 0UL; // CPU cycle counter
ulong memoryAllocations = 0UL; // Memory allocation counter
// 64-bit unique IDs
ulong GenerateUniqueID()
{
// Combine timestamp with random value
ulong timestamp = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds();
ulong random = (ulong)Random.Shared.NextInt64();
return (timestamp << 32) | (random & 0xFFFFFFFF);
}
Common pitfalls
// PITFALL 1: Subtraction wraps (same as uint, but BIGGER!)
ulong a = 10UL;
ulong b = 20UL;
ulong result = a - b; // Result = 18,446,744,073,709,551,606 (NOT -10!)
// Fix: Check before subtracting
if (a >= b)
{
ulong diff = a - b;
}
else
{
// Handle case where a < b
ulong diff = b - a; // Or use 0, or error
}
// Or use long for signed calculations
long signedDiff = (long)a - (long)b; // -10 (if values fit in long)
// PITFALL 2: Countdown loop (INFINITE LOOP!)
for (ulong i = 10UL; i >= 0; i--) // Never terminates!
{
// When i = 0, i-- wraps to 18,446,744,073,709,551,615!
}
// Fix: Use int or long for loops
for (long i = 10; i >= 0; i--) // Works
// PITFALL 3: Comparing with signed types
ulong unsigned = 100UL;
long signed = -50L;
if (unsigned > signed) // Dangerous conversion!
{
// signed becomes huge positive when converted to ulong
}
// PITFALL 4: Forgetting 'UL' suffix for large literals
ulong big = 10000000000000000000; // Error! Too large
ulong big = 10000000000000000000UL; // Correct
// PITFALL 5: Overflow at max value
ulong max = ulong.MaxValue; // 18,446,744,073,709,551,615
max += 1UL; // Wraps to 0!
// Fix: Check before incrementing
if (max < ulong.MaxValue)
{
max++;
}
// PITFALL 6: Implicit conversion issues
ulong value = 100UL;
int smallInt = (int)value; // Data loss if value > int.MaxValue!
// Always check
if (value <= int.MaxValue)
{
int safe = (int)value;
}
// PITFALL 7: Mixing with float/double (precision loss)
ulong huge = 10000000000000000000UL;
double result = huge; // Precision loss! double can't represent all ulong values exactly
Pro tips
// TIP 1: Use for file system operations (handles > 16 exabyte files)
ulong GetTotalDiskSpace(string drive)
{
DriveInfo info = new DriveInfo(drive);
return (ulong)info.TotalSize;
}
string FormatBytes(ulong bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
int order = 0;
double size = bytes;
while (size >= 1024 && order < sizes.Length - 1)
{
order++;
size /= 1024;
}
return $"{size:F2} {sizes[order]}";
}
// TIP 2: 64-bit hash function
ulong Hash64(string input)
{
ulong hash = 0;
foreach (char c in input)
{
hash = hash * 31UL + c;
}
return hash;
}
// FNV-1a hash (better distribution)
ulong FNV1aHash(byte[] data)
{
const ulong FNV_OFFSET_BASIS = 14695981039346656037UL;
const ulong FNV_PRIME = 1099511628211UL;
ulong hash = FNV_OFFSET_BASIS;
foreach (byte b in data)
{
hash ^= b;
hash *= FNV_PRIME;
}
return hash;
}
// TIP 3: Rarely needed - consider if long is sufficient
// long max = ±9.2 quintillion
// ulong max = 18.4 quintillion (positive only)
// Do you REALLY need 18 quintillion?
// TIP 4: Bit manipulation for large values
ulong flags = 0UL;
ulong FLAG_BIT_63 = 1UL << 63; // Can use all 64 bits!
flags |= FLAG_BIT_63; // Set bit 63
bool isSet = (flags & FLAG_BIT_63) != 0; // Check bit 63
// TIP 5: Unique ID generation
ulong GenerateSnowflakeID()
{
// Twitter Snowflake-like ID
long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
int machineID = 1; // Your machine ID
int sequence = 0; // Sequence number
ulong id = ((ulong)timestamp << 22) | ((ulong)machineID << 12) | (ulong)sequence;
return id;
}
// TIP 6: Check if value fits in ulong
bool FitsInULong(decimal value)
{
return value >= 0 && value <= ulong.MaxValue;
}
bool FitsInLong(ulong value)
{
return value <= long.MaxValue;
}
// TIP 7: Safe arithmetic operations
ulong SafeAdd(ulong a, ulong b)
{
if (a > ulong.MaxValue - b)
return ulong.MaxValue; // Would overflow
return a + b;
}
ulong SafeSubtract(ulong a, ulong b)
{
if (a < b)
return 0; // Would wrap
return a - b;
}
ulong SafeMultiply(ulong a, ulong b)
{
if (a > 0 && b > ulong.MaxValue / a)
return ulong.MaxValue; // Would overflow
return a * b;
}
// TIP 8: Conversion helpers
ulong BytesToULong(byte[] bytes, int offset)
{
return BitConverter.ToUInt64(bytes, offset);
}
byte[] ULongToBytes(ulong value)
{
return BitConverter.GetBytes(value);
}
// TIP 9: Cryptocurrency calculations
ulong SatoshisToBitcoin(ulong satoshis)
{
return satoshis / 100000000UL; // 1 BTC = 100M satoshis
}
ulong BitcoinToSatoshis(double bitcoin)
{
return (ulong)(bitcoin * 100000000.0);
}
// TIP 10: Comparison with proper overflow handling
bool IsGreater(ulong a, ulong b)
{
return a > b; // Simple for ulong
}
// For wrapping counters (like sequence numbers)
bool IsNewer(ulong current, ulong received)
{
const ulong HALF_MAX = ulong.MaxValue / 2;
ulong diff = received - current;
return diff > 0 && diff < HALF_MAX;
}
// TIP 11: Use constants for large values
const ulong BYTES_PER_KILOBYTE = 1024UL;
const ulong BYTES_PER_MEGABYTE = 1024UL * 1024UL;
const ulong BYTES_PER_GIGABYTE = 1024UL * 1024UL * 1024UL;
const ulong BYTES_PER_TERABYTE = 1024UL * 1024UL * 1024UL * 1024UL;
// TIP 12: ALWAYS use int/long for loops, never ulong!
// WRONG:
for (ulong i = 10; i >= 0; i--) // Infinite!
// CORRECT:
for (long i = 10; i >= 0; i--) // Works
02 Floating point types (decimal numbers)
These types handle numbers with fractional parts (decimals). Critical for physics, positions, and any calculations requiring precision.
float — Unity/Unreal standard
Beginner explanation: The standard way to store decimal numbers in game engines (Unity/Unreal). Can store numbers like 3.14, -0.5, or 1000.75. Has about 6-7 digits of precision, which is enough for most game physics, positions, and rotations. ALWAYS add 'f' after the number (like 5.0f) to tell the compiler it's a float!
Technical specs
- Size: 4 bytes (32 bits)
- Precision: ~6-7 significant digits
- Range: ±1.5 × 10⁻⁴⁵ to ±3.4 × 10³⁸
- Default Value: 0.0f
Performance notes
- Fast - hardware accelerated on all platforms
- GPU prefers float (Vector/Matrix math)
- Half memory of double (4 vs 8 bytes)
- Unity/Unreal use float as standard
- ~6-7 digits precision (errors accumulate!)
- Large + small numbers lose small value
- Unity standard - use float everywhere in Unity
- Performance: Faster than double on some platforms
When to use float
- Unity/Unreal game development (always!)
- 3D positions, rotations, scales
- Physics (velocity, acceleration, forces)
- Game timers, cooldowns
- UI values (alpha, scale, position)
- Audio (volume, pitch, pan)
- Don't use for money/currency (precision errors!)
- Don't use for exact equality comparisons
Syntax and declaration
// CRITICAL: Always add 'f' suffix!
float speed = 5.5f; // Correct
float gravity = -9.8f; // Correct
float wrong = 5.5; // Compiler warning! Treated as double
// Basic operations
float positionX = 10.5f;
float positionY = -3.2f;
float positionZ = 0.0f;
// Unity/Unreal examples (they use float everywhere!)
float health = 100.0f;
float moveSpeed = 5.0f;
float jumpForce = 7.5f;
float rotationSpeed = 90.0f; // Degrees per second
// Scientific notation
float small = 1.5e-10f; // 0.00000000015
float large = 3.4e38f; // 340,000,000,000,000,000,000,000,000,000,000,000,000
Practical use cases
// Unity Transform (ALL use float)
float posX = transform.position.x;
float posY = transform.position.y;
float posZ = transform.position.z;
// Physics
float velocity = 10.5f;
float acceleration = 9.8f;
float mass = 50.0f;
float friction = 0.3f;
float drag = 0.1f;
// Game mechanics
float attackSpeed = 1.5f; // Attacks per second
float cooldown = 3.0f; // Seconds
float damageMultiplier = 1.25f;
float critChance = 0.15f; // 15% (0.0 to 1.0)
float dodgeChance = 0.08f; // 8%
// Animation
float animationTime = 0.0f;
float blendWeight = 0.5f; // 0.0 to 1.0
float transitionSpeed = 2.0f;
float animationSpeed = 1.5f; // Playback speed multiplier
// UI/Screen
float alpha = 0.8f; // Transparency (0.0 to 1.0)
float scale = 1.5f; // Size multiplier
float fadeSpeed = 1.0f;
float uiPosition = 100.0f; // Screen position
// Time
float deltaTime = Time.deltaTime; // Unity's frame time
float elapsed = 0.0f;
float duration = 5.0f;
float timeRemaining = 10.0f;
// Audio
float volume = 0.75f; // 0.0 to 1.0
float pitch = 1.2f; // Pitch multiplier
float pan = -0.5f; // -1.0 (left) to 1.0 (right)
// Camera
float fieldOfView = 60.0f; // FOV in degrees
float nearClip = 0.1f;
float farClip = 1000.0f;
float cameraSpeed = 5.0f;
// Movement
Vector3 direction = new Vector3(1.0f, 0.0f, 0.0f); // Normalized direction
float moveSpeed = 5.0f;
float sprintMultiplier = 1.5f;
float crouchMultiplier = 0.5f;
// Color (normalized 0-1)
float red = 1.0f;
float green = 0.5f;
float blue = 0.0f;
Color color = new Color(red, green, blue, 1.0f);
Common pitfalls
// PITFALL 1: Forgetting 'f' suffix
float value = 5.5; // Warning! Implicitly converted from double
float value = 5.5f; // Correct
// PITFALL 2: Precision errors (inherent to floating point)
float a = 0.1f;
float b = 0.2f;
float c = a + b; // c = 0.30000001f (not exactly 0.3!)
// Never use == for float comparison!
if (c == 0.3f) // Might fail due to precision!
{
// Use epsilon comparison instead
}
// Correct way:
float epsilon = 0.0001f;
if (Mathf.Abs(c - 0.3f) < epsilon) // Within tolerance
{
// Close enough!
}
// Unity helper:
if (Mathf.Approximately(a, b)) // Best for Unity
{
// Values are "close enough"
}
// PITFALL 3: Large number + small number loses precision
float big = 1000000.0f;
float small = 0.0001f;
float result = big + small; // result = 1000000.0f (small value lost!)
// PITFALL 4: Comparing to zero
float velocity = CalculateVelocity();
if (velocity == 0.0f) // Might never be exactly zero!
if (Mathf.Abs(velocity) < 0.01f) // Better (check if close to zero)
// PITFALL 5: Division by zero
float result = 10.0f / 0.0f; // result = Infinity (not an error!)
float nan = 0.0f / 0.0f; // result = NaN (Not a Number)
// Check for invalid values
if (float.IsInfinity(result)) // Check for infinity
if (float.IsNaN(nan)) // Check for NaN
if (!float.IsFinite(value)) // Check if NOT (NaN or Infinity)
// PITFALL 6: Accumulation errors
float sum = 0.0f;
for (int i = 0; i < 1000000; i++)
{
sum += 0.1f; // Errors accumulate!
}
// sum will NOT be exactly 100000.0f
// PITFALL 7: Precision loss with integers
int largeInt = 16777217; // More than 7 digits
float converted = largeInt; // Precision loss!
int backToInt = (int)converted; // Might not equal original!
// float can only precisely represent integers up to 16,777,216
// PITFALL 8: Order of operations matters
float a = 1000000.0f;
float b = 1.0f;
float c = 0.1f;
float result1 = (a + b) + c; // Different from...
float result2 = a + (b + c); // ...this! (due to precision)
Pro tips
// TIP 1: Unity helper functions
float clamped = Mathf.Clamp(value, 0.0f, 1.0f); // Clamp between 0 and 1
float clamped01 = Mathf.Clamp01(value); // Same as above (shortcut)
float lerped = Mathf.Lerp(start, end, 0.5f); // Linear interpolation
float smoothed = Mathf.SmoothStep(0.0f, 1.0f, t); // Smooth interpolation
// TIP 2: Use Mathf.Approximately for comparisons (Unity)
if (Mathf.Approximately(a, b)) // Handles floating point precision
{
// Values are "close enough"
}
// TIP 3: Normalize percentages (0 to 1)
float healthPercent = currentHealth / maxHealth; // 0.0 to 1.0
float progress = elapsedTime / totalTime; // 0.0 to 1.0
// Use in UI
healthBar.fillAmount = healthPercent;
progressBar.fillAmount = progress;
// TIP 4: Convert degrees to radians (and back)
float degrees = 90.0f;
float radians = degrees * Mathf.Deg2Rad; // 1.5708f (π/2)
float backToDegrees = radians * Mathf.Rad2Deg; // 90.0f
// TIP 5: Common mathematical constants (Unity)
float pi = Mathf.PI; // 3.14159265f
float tau = Mathf.PI * 2.0f; // 6.28318531f (full circle)
float halfPi = Mathf.PI / 2.0f; // 90 degrees
float epsilon = Mathf.Epsilon; // Smallest positive float
// TIP 6: Use const for unchanging values
const float GRAVITY = -9.8f;
const float MAX_SPEED = 100.0f;
const float JUMP_FORCE = 5.0f;
// TIP 7: Smooth movement with Lerp
float currentPos = 0.0f;
float targetPos = 10.0f;
float smoothSpeed = 5.0f;
void Update()
{
// Smooth interpolation
currentPos = Mathf.Lerp(currentPos, targetPos, Time.deltaTime * smoothSpeed);
}
// TIP 8: Exponential smoothing (better than Lerp for following)
float ExponentialSmoothing(float current, float target, float smoothTime, float deltaTime)
{
return Mathf.Lerp(current, target, 1.0f - Mathf.Exp(-deltaTime / smoothTime));
}
// TIP 9: Check for valid numbers before using
float CheckedDivide(float a, float b)
{
if (Mathf.Abs(b) < 0.0001f) return 0.0f; // Avoid division by ~zero
float result = a / b;
if (float.IsNaN(result) || float.IsInfinity(result))
{
return 0.0f; // Return safe default
}
return result;
}
// TIP 10: Remap values between ranges
float Remap(float value, float fromMin, float fromMax, float toMin, float toMax)
{
float t = (value - fromMin) / (fromMax - fromMin); // Normalize to 0-1
return Mathf.Lerp(toMin, toMax, t); // Map to new range
}
// Example: Convert 0-100 health to 0-1 alpha
float healthAlpha = Remap(health, 0.0f, 100.0f, 0.0f, 1.0f);
// TIP 11: Ping-pong values (oscillate between min and max)
float oscillating = Mathf.PingPong(Time.time, 1.0f); // 0 to 1 and back
// TIP 12: Smooth Damp (Unity's smooth movement helper)
float currentVelocity = 0.0f;
float smoothTime = 0.3f;
void Update()
{
currentPos = Mathf.SmoothDamp(currentPos, targetPos, ref currentVelocity, smoothTime);
}
// TIP 13: InverseLerp (find percentage between two values)
float percentage = Mathf.InverseLerp(minHealth, maxHealth, currentHealth);
// If currentHealth = 50, minHealth = 0, maxHealth = 100 → percentage = 0.5
// TIP 14: Move towards (move by fixed step, don't overshoot)
float MoveTowards(float current, float target, float maxDelta)
{
return Mathf.MoveTowards(current, target, maxDelta);
}
void Update()
{
position = Mathf.MoveTowards(position, targetPosition, speed * Time.deltaTime);
}
// TIP 15: Sign function (get direction: -1, 0, or 1)
float direction = Mathf.Sign(velocity); // -1 if negative, 1 if positive, 0 if zero
// TIP 16: Repeat (wrap values in range)
float wrapped = Mathf.Repeat(value, length); // Wraps value between 0 and length
double — C# math standard
Beginner explanation: More precise version of float with ~15-16 digits of accuracy. The default decimal type in C# (when you write 5.5 without 'f', it's a double). Use for scientific calculations, math libraries, or when you need more precision than float. Slower and uses more memory than float, but much more accurate.
Technical specs
- Size: 8 bytes (64 bits)
- Precision: ~15-16 significant digits
- Range: ±5.0 × 10⁻³²⁴ to ±1.7 × 10³⁰⁸
Default Value: 0.0
Performance notes
- Fast on 64-bit systems (native register size)
- Slower than float on some platforms (~10-30% slower)
- Uses 2x memory of float (8 vs 4 bytes)
- Math class uses double (no conversion overhead)
- Better precision for scientific calculations
- C# standard for math operations
Unity: Stick with float; convert from double only when needed
When to use double
- Scientific calculations
- Math library operations (Math.Sin, Math.Sqrt, etc.)
- High-precision requirements (astronomy, physics simulations)
- Statistical analysis
- General C# programming (non-Unity)
- Don't use in Unity (use float instead)
- Don't use for money (use decimal!)
- Don't use in performance-critical loops if float is sufficient
Syntax and declaration
// No suffix needed (double is default for decimals)
double pi = 3.14159265358979; // High precision
double scientific = 1.23e-100; // Very small number
double large = 1.79e308; // Very large number
// Explicit double (optional 'd' suffix)
double explicit = 5.5d; // Same as 5.5
double withoutSuffix = 5.5; // Also double
// Common uses
double distance = 384400000.0; // Earth to Moon (meters)
double precise = 0.123456789012345; // Many decimal places
double calculation = Math.PI * Math.E; // Math class uses double
Practical use cases
// Scientific calculations
double speedOfLight = 299792458.0; // m/s (exact value)
double gravityConstant = 6.67430e-11; // N⋅m²/kg²
double avogadro = 6.02214076e23; // Avogadro's number
double electronMass = 9.10938356e-31; // kg
// Math library (System.Math uses double)
double angle = Math.PI / 4.0; // 45 degrees in radians
double sine = Math.Sin(angle); // Trigonometry
double cosine = Math.Cos(angle);
double tangent = Math.Tan(angle);
double root = Math.Sqrt(value); // Square root
double power = Math.Pow(2.0, 10.0); // Exponentiation (1024)
double log = Math.Log(100.0); // Natural logarithm
double log10 = Math.Log10(100.0); // Base-10 logarithm (2)
// Financial calculations (better than float, but use decimal for money!)
double interestRate = 0.0425; // 4.25%
double balance = 10000.0;
double interest = balance * interestRate; // Better precision than float
// Astronomy/Space games (huge distances)
double astronomicalUnit = 149597870700.0; // 1 AU in meters
double lightYear = 9.461e15; // 1 light year in meters
double distanceToProxima = 4.0217 * lightYear; // Proxima Centauri
double parsec = 3.0857e16; // 1 parsec in meters
// High-precision timers
double preciseTime = (double)DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
double elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
double elapsedMs = stopwatch.Elapsed.TotalMilliseconds;
// Statistical calculations
double[] values = { 10.5, 20.3, 15.7, 30.1, 25.9 };
double mean = values.Average(); // LINQ returns double
double sum = values.Sum(); // LINQ returns double
double standardDeviation = CalculateStdDev(values);
double CalculateStdDev(double[] values)
{
double mean = values.Average();
double sumOfSquares = values.Sum(v => Math.Pow(v - mean, 2.0));
return Math.Sqrt(sumOfSquares / values.Length);
}
// Physics simulations (high precision)
double position = 0.0;
double velocity = 0.0;
double acceleration = 9.8;
double time = 0.0;
void Simulate(double deltaTime)
{
velocity += acceleration * deltaTime;
position += velocity * deltaTime;
}
// Geographic coordinates (GPS precision)
double latitude = 40.7128; // New York latitude
double longitude = -74.0060; // New York longitude
double altitude = 10.5; // Meters above sea level
// Mathematical constants (high precision)
const double PI = 3.14159265358979323846;
const double E = 2.71828182845904523536;
const double GOLDEN_RATIO = 1.61803398874989484820;
const double SQRT_2 = 1.41421356237309504880;
Common pitfalls
// PITFALL 1: Mixing float and double (implicit conversions)
float f = 5.5f;
double d = f; // OK - float → double (safe, no data loss)
double d2 = 5.5;
float f2 = d2; // Error! double → float (requires explicit cast)
float f2 = (float)d2; // OK, but possible precision loss
// PITFALL 2: Same precision issues as float (but smaller)
double a = 0.1;
double b = 0.2;
double c = a + b; // c = 0.30000000000000004 (not exactly 0.3!)
// Use epsilon comparison
const double EPSILON = 1e-10; // Smaller epsilon for double
if (Math.Abs(c - 0.3) < EPSILON) // Close enough
{
// Values are equal within tolerance
}
// PITFALL 3: Performance cost (slower than float)
// In tight loops with millions of iterations, float is faster
for (int i = 0; i < 1000000; i++)
{
double calc = Math.Sin(i); // Slower than float version
}
// PITFALL 4: Unity doesn't use double! (uses float)
Vector3 position = new Vector3(1.0, 2.0, 3.0); // Actually float!
// If you calculate with double, you'll need to cast:
double calculation = GetDoubleValue();
transform.position = new Vector3((float)calculation, 0, 0);
// PITFALL 5: Integer division still applies
double result = 10 / 3; // 3.0 (not 3.333!) - integer division first!
double correct = 10.0 / 3.0; // 3.333... - double division
// PITFALL 6: Large number + small number (less severe than float)
double big = 1e15;
double small = 1.0;
double result = big + small; // Might lose small value (but better than float)
// PITFALL 7: Infinity and NaN
double infinity = 1.0 / 0.0; // Infinity
double negInfinity = -1.0 / 0.0; // -Infinity
double nan = 0.0 / 0.0; // NaN
if (double.IsInfinity(infinity)) // true
if (double.IsNaN(nan)) // true
if (!double.IsFinite(value)) // Check if NOT (NaN or Infinity)
Pro tips
// TIP 1: Math class functions use double
double angle = Math.PI / 4.0; // 45 degrees in radians
double sine = Math.Sin(angle);
double cosine = Math.Cos(angle);
double tangent = Math.Tan(angle);
double arcSin = Math.Asin(0.5); // Inverse trig
double arcCos = Math.Acos(0.5);
double arcTan = Math.Atan(1.0);
// TIP 2: Use for precise percentage calculations
double percentage = (currentValue / totalValue) * 100.0;
double accurate = (123.0 / 456.0) * 100.0; // 26.973684210526315%
// TIP 3: High-precision constants
const double PI = 3.14159265358979323846;
const double E = 2.71828182845904523536;
const double GOLDEN_RATIO = 1.61803398874989484820;
const double PHI = 1.61803398874989484820; // Golden ratio
const double SQRT_2 = 1.41421356237309504880;
const double SQRT_3 = 1.73205080756887729352;
// TIP 4: TimeSpan uses double for time units
TimeSpan duration = TimeSpan.FromSeconds(123.456);
double totalSeconds = duration.TotalSeconds; // 123.456
double totalMinutes = duration.TotalMinutes; // 2.0576
double totalHours = duration.TotalHours; // 0.03429333...
// TIP 5: LINQ Average/Sum return double
int[] numbers = { 1, 2, 3, 4, 5 };
double average = numbers.Average(); // Returns double (3.0)
double sum = numbers.Sum(); // Returns double (15.0)
// TIP 6: Converting between float and double safely
float floatValue = 5.5f;
double doubleValue = floatValue; // Implicit (safe)
double preciseValue = 5.123456789;
float lessPrecise = (float)preciseValue; // Explicit cast (precision loss)
// TIP 7: Use double for intermediate calculations, convert to float at end
double calculation = Math.Sqrt(a * a + b * b); // High precision
float finalResult = (float)calculation; // Convert for Unity
// TIP 8: Comparison helper function
bool ApproximatelyEqual(double a, double b, double epsilon = 1e-10)
{
return Math.Abs(a - b) < epsilon;
}
// Usage
if (ApproximatelyEqual(result, expected))
{
// Values match within tolerance
}
// TIP 9: Distance calculations (high precision)
double Distance2D(double x1, double y1, double x2, double y2)
{
double dx = x2 - x1;
double dy = y2 - y1;
return Math.Sqrt(dx * dx + dy * dy);
}
// TIP 10: Rounding to specific decimal places
double value = 3.14159265359;
double rounded2 = Math.Round(value, 2); // 3.14
double rounded5 = Math.Round(value, 5); // 3.14159
// Different rounding modes
double rounded = Math.Round(2.5, MidpointRounding.AwayFromZero); // 3
double banker = Math.Round(2.5, MidpointRounding.ToEven); // 2 (banker's rounding)
// TIP 11: Ceiling and Floor
double value = 3.7;
double ceil = Math.Ceiling(value); // 4.0
double floor = Math.Floor(value); // 3.0
double truncate = Math.Truncate(value); // 3.0 (remove decimals)
// TIP 12: Clamping values
double Clamp(double value, double min, double max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
double clamped = Math.Clamp(value, 0.0, 1.0); // .NET 6+
// TIP 13: Lerp for doubles
double Lerp(double a, double b, double t)
{
return a + (b - a) * t;
}
double interpolated = Lerp(0.0, 100.0, 0.5); // 50.0
// TIP 14: InverseLerp for doubles
double InverseLerp(double a, double b, double value)
{
return (value - a) / (b - a);
}
double t = InverseLerp(0.0, 100.0, 75.0); // 0.75
// TIP 15: Exponential functions
double exp = Math.Exp(2.0); // e^2
double ln = Math.Log(value); // Natural log
double log10 = Math.Log10(value); // Base-10 log
double log2 = Math.Log2(value); // Base-2 log (.NET 6+)
// TIP 16: Min and Max
double min = Math.Min(a, b);
double max = Math.Max(a, b);
// Multiple values
double minimum = new[] { 1.5, 2.3, 0.8, 3.7 }.Min();
double maximum = new[] { 1.5, 2.3, 0.8, 3.7 }.Max();
// TIP 17: Absolute value and Sign
double abs = Math.Abs(-5.5); // 5.5
int sign = Math.Sign(-5.5); // -1 (negative), 0 (zero), 1 (positive)
// TIP 18: Convert string to double safely
string input = "123.456";
if (double.TryParse(input, out double result))
{
// result = 123.456
}
// With culture-specific parsing
double value = double.Parse("123.456", System.Globalization.CultureInfo.InvariantCulture);
03 References
- [01]DOCS — Built-in types and literals.
learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/built-in-types - [02]DOCS — Integral numeric types.
learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types
- 01Overview & Integer Typesint · byte · sbyte · short · ushortLIVE
- 02Unsigned & Floating-Point Typesuint · long · ulong · float · doubleCURRENT
- 03Decimal, Char, String & Booldecimal · char · string · boolLIVE