C # พฤติกรรมล้นสำหรับ uint ไม่ จำกัด


10

ฉันทดสอบโค้ดนี้ที่https://dotnetfiddle.net/ :

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)));
        Console.WriteLine(unchecked((uint)(ulong)(scale* scale + 7)));
    }
}

ถ้าฉันรวบรวมด้วย. NET 4.7.2 ฉันจะได้รับ

859091763

7

แต่ถ้าฉันทำ Roslyn หรือ. NET Core ฉันจะได้รับ

859091763

0

ทำไมสิ่งนี้ถึงเกิดขึ้น


cast to ulongกำลังถูกละเว้นในกรณีหลังดังนั้นจึงเกิดขึ้นในการแปลงfloat-> int
madreflection

ฉันแปลกใจมากขึ้นจากการเปลี่ยนแปลงพฤติกรรมซึ่งดูเหมือนจะแตกต่างกันมาก ฉันไม่คาดหวังว่า "0" จะเป็นคำตอบที่ถูกต้องอย่างใดอย่างหนึ่งกับ chain of casts tbh
ลูคัส

เข้าใจได้ หลายสิ่งในสเป็คได้รับการแก้ไขในคอมไพเลอร์เมื่อพวกเขาสร้างโรสลินเพื่อที่จะได้เป็นส่วนหนึ่งของมัน ตรวจสอบเอาต์พุต JIT ของรุ่นนี้บน SharpLab นั่นแสดงว่านักแสดงulongมีผลต่อผลลัพธ์อย่างไร
madreflection

มันเป็นเรื่องที่น่าทึ่งด้วยตัวอย่างของคุณบน dotnetfiddle ผลสุดท้ายของ WriteLine 0 ใน Roslyn 3.4 และ 7 บน. NET Core 3.1
Lukas

ฉันยังยืนยันบนเดสก์ท็อปของฉัน รหัส JIT ไม่ได้มองอย่างใกล้ชิดเลยฉันได้ผลลัพธ์ที่แตกต่างกันระหว่าง. NET Core และ. NET Framework Trippy
Lukas

คำตอบ:


1

ข้อสรุปของฉันไม่ถูกต้อง ดูการอัปเดตสำหรับรายละเอียดเพิ่มเติม

ดูเหมือนว่าบั๊กในคอมไพเลอร์ตัวแรกที่คุณใช้ Zero เป็นผลลัพธ์ที่ถูกต้องในกรณีนี้ ลำดับของการดำเนินการที่กำหนดโดยข้อกำหนด C # มีดังนี้:

  1. คูณscaleด้วยscaleยอมa
  2. ดำเนินการa + 7ยอมแพ้b
  3. โยนbเพื่อulongยอมแพ้c
  4. โยนcเพื่อuintยอมแพ้d

b = 4.2949673E+09fสองการดำเนินงานครั้งแรกที่ทำให้คุณมีค่าลอย ภายใต้การคำนวณเลขทศนิยมมาตรฐานนี่คือ 4294967296( คุณสามารถตรวจสอบได้ที่นี่ ) ที่เหมาะสมในulongการปรับเพียงเพื่อให้c = 4294967296แต่มันก็เป็นสิ่งหนึ่งมากกว่า uint.MaxValueดังนั้นจึงรอบการเดินทางไปจึง0 d = 0ตอนนี้แปลกใจแปลกใจตั้งแต่จุดลอยเลขคณิตเป็นขี้ขลาด4.2949673E+09fและ4.2949673E+09f + 7เป็นจำนวนเดียวกันแน่นอนใน IEEE 754 ดังนั้นscale * scaleจะให้ค่าเดียวกันของfloatเป็นscale * scale + 7, a = bเพื่อให้การดำเนินงานที่สองเป็นพื้นไม่มี-op

คอมไพเลอร์ Roslyn ทำการดำเนินการ const (บางส่วน) ณ เวลารวบรวมและปรับการแสดงออกทั้งหมดให้0เป็น อีกครั้งนั่นคือผลลัพธ์ที่ถูกต้องและคอมไพเลอร์ได้รับอนุญาตให้ดำเนินการเพิ่มประสิทธิภาพใด ๆ ที่จะส่งผลให้พฤติกรรมเช่นเดียวกับรหัสโดยไม่มีพวกเขา

ฉันเดาว่าคอมไพเลอร์. NET 4.7.2 ที่คุณใช้ยังพยายามปรับแต่งสิ่งนี้ให้ดีที่สุด แต่มีข้อผิดพลาดที่ทำให้การประเมินการส่งผิดในที่ที่ไม่ถูกต้อง ธรรมชาติถ้าคุณโยนครั้งแรกscaleไปยังuintและจากนั้นดำเนินการคุณจะได้รับ7เพราะscale * scaleตลอดการเดินทางไปและจากนั้นคุณเพิ่ม0 7แต่ที่ไม่สอดคล้องกับผลที่คุณจะได้รับเมื่อมีการประเมินการแสดงออกขั้นตอนโดยขั้นตอนที่รันไทม์ อีกครั้งสาเหตุที่แท้จริงเป็นเพียงการคาดเดาเมื่อดูที่พฤติกรรมที่ผลิต แต่ให้ทุกอย่างที่ฉันได้กล่าวไว้ข้างต้นฉันเชื่อว่านี่เป็นการละเมิดข้อมูลจำเพาะด้านข้างของคอมไพเลอร์แรก

UPDATE:

ฉันทำผิดไปแล้ว มีข้อกำหนด C # นี้เล็กน้อยที่ฉันไม่ทราบว่ามีอยู่เมื่อเขียนคำตอบข้างต้น:

การดำเนินการจุดลอยตัวอาจดำเนินการด้วยความแม่นยำสูงกว่าประเภทผลลัพธ์ของการดำเนินการ ตัวอย่างเช่นสถาปัตยกรรมฮาร์ดแวร์บางตัวรองรับชนิดทศนิยมแบบ "ขยาย" หรือ "ยาวสองเท่า" ที่มีช่วงและความแม่นยำมากกว่าประเภทสองและดำเนินการกับจุดลอยตัวทั้งหมดโดยใช้ประเภทความแม่นยำสูงกว่านี้ มีเพียงค่าใช้จ่ายที่มากเกินไปในการทำงานเท่านั้นที่จะสามารถสร้างสถาปัตยกรรมฮาร์ดแวร์ดังกล่าวเพื่อดำเนินการจุดลอยตัวที่มีความแม่นยำน้อยกว่าและแทนที่จะต้องการการปรับใช้ทั้งประสิทธิภาพและความแม่นยำ C # อนุญาตให้ใช้ประเภทความแม่นยำสูงกว่า . นอกเหนือจากการให้ผลลัพธ์ที่แม่นยำยิ่งขึ้นสิ่งนี้ไม่ค่อยมีผลกระทบใด ๆ ที่วัดได้ อย่างไรก็ตามในการแสดงออกของรูปแบบ x * y / z

C # ค้ำประกันการดำเนินงานเพื่อให้ระดับของความแม่นยำอย่างน้อยในระดับของ IEEE 754 แต่ไม่จำเป็นต้องตรงว่า ไม่ใช่ข้อผิดพลาดมันเป็นคุณสมบัติสเป็ค คอมไพเลอร์โรสลินอยู่ในตัวของมันในการประเมินการแสดงออกตรงตามมาตรฐาน IEEE 754 ระบุและคอมไพเลอร์อื่น ๆ ที่อยู่ในตัวของมันที่จะอนุมานได้ว่า2^32 + 7เป็นเมื่อใส่ลงไปใน7uint

ฉันขอโทษสำหรับคำตอบแรกที่ทำให้เข้าใจผิด แต่อย่างน้อยเราก็ได้เรียนรู้บางสิ่งบางอย่างในวันนี้


จากนั้นฉันเดาว่าเรามีข้อผิดพลาดในคอมไพเลอร์. NET Framework ปัจจุบัน (ฉันเพิ่งลองใน VS 2019 เพื่อให้แน่ใจ) :) ฉันเดาว่าฉันจะลองดูว่ามีที่ไหนซักแห่งที่จะบันทึกบั๊ก แต่ก็แก้ไขสิ่งที่ต้องการ อาจมีผลข้างเคียงที่ไม่ต้องการจำนวนมากและอาจถูกเพิกเฉย ...
ลูกา

ฉันไม่คิดว่ามันจะทำการคัดเลือกก่อนกำหนดซึ่งจะทำให้เกิดปัญหาที่ชัดเจนมากขึ้นในหลาย ๆ กรณีฉันคิดว่ากรณีที่นี่คือในการดำเนินการ const ที่ไม่ได้ประเมินค่าและการหล่อจนกว่าจะถึงความหมายสุดท้าย คือแทนที่จะเก็บค่ากลางในการลอยตัวมันแค่ข้ามไปและแทนที่มันในแต่ละนิพจน์ด้วยนิพจน์นั้นเอง
jalsh

@jalsh ฉันไม่คิดว่าฉันเข้าใจการเดาของคุณ หากคอมไพเลอร์เพียงแทนที่แต่ละscaleด้วยค่าลอยและประเมินทุกอย่างอื่นที่รันไทม์ผลลัพธ์จะเหมือนกัน คุณสามารถทำอย่างละเอียด?
V0ldek

@ V0ldek, downvote เป็นความผิดพลาดที่ผมแก้ไขคำตอบของคุณดังนั้นฉันสามารถเอามันออกไป :)
jalsh

ฉันเดาว่ามันไม่ได้จริงเก็บค่ากลางในการลอยก็แค่แทนที่ F มีการแสดงออกที่ประเมินฉโดยไม่ต้องหล่อมันจะลอย
jalsh

0

จุดนี่คือ (ตามที่คุณสามารถเห็นในเอกสาร ) ที่ลอยค่าสามารถมีเพียงฐานถึง2 ^ 24 ดังนั้นเมื่อคุณกำหนดค่าเป็น2 ^ 32 ( 64 * 2014 * 164 * 1024 = 2 ^ 6 * 2 ^ 10 * 2 ^ 6 * 2 ^ 10 = 2 ^ 32 ) มันจะกลายเป็นจริง2 ^ 24 * 2 ^ 8ซึ่งเป็น4294967000 เพิ่ม7จะได้รับการเพิ่มในส่วนที่ถูกตัดออกจากการแปลงไปยังอู่ล่อง

หากคุณเปลี่ยนเป็นสองเท่าซึ่งมีฐานเป็น2 ^ 53มันจะทำงานกับสิ่งที่คุณต้องการ

นี่อาจเป็นปัญหารันไทม์ แต่ในกรณีนี้มันเป็นปัญหาเวลาคอมไพล์เนื่องจากค่าทั้งหมดเป็นค่าคงที่และจะถูกประเมินโดยคอมไพเลอร์


-2

ก่อนอื่นคุณกำลังใช้บริบทที่ไม่ได้ตรวจสอบซึ่งเป็นคำสั่งสำหรับคอมไพเลอร์ที่คุณแน่ใจว่าเป็นนักพัฒนาว่าผลลัพธ์จะไม่ล้นประเภทและคุณต้องการเห็นข้อผิดพลาดในการรวบรวม ในสถานการณ์ของคุณจริง ๆ แล้วคุณมีวัตถุประสงค์ในการโอเวอร์โฟลว์ประเภทและคาดว่าจะมีพฤติกรรมที่สอดคล้องกันในคอมไพเลอร์สามตัวซึ่งหนึ่งในนั้นอาจจะเข้ากันได้ย้อนหลังไปไกลจนถึงประวัติศาสตร์เมื่อเปรียบเทียบกับ Roslyn และ. NET Core

สิ่งที่สองคือคุณกำลังผสมการแปลงโดยนัยและชัดเจน ฉันไม่แน่ใจเกี่ยวกับคอมไพเลอร์ Roslyn แต่คอมไพเลอร์. NET Framework และ. NET Core อาจใช้การเพิ่มประสิทธิภาพที่แตกต่างกันสำหรับการดำเนินการเหล่านั้น

ปัญหาที่นี่คือบรรทัดแรกของรหัสของคุณใช้เฉพาะค่า / ประเภทจุดลอยตัว แต่บรรทัดที่สองคือการรวมกันของค่า / ชนิดจุดลอยตัวและค่า / ชนิดสำคัญ

ในกรณีที่คุณทำจำนวนจุดลอยตัวจำนวนเต็มทันที (7> 7.0) คุณจะได้รับผลลัพธ์ที่เหมือนกันมากสำหรับแหล่งข้อมูลทั้งสามที่รวบรวม

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale))); // 859091763
        Console.WriteLine(unchecked((uint)(ulong)(scale * scale + 7.0))); // 7
    }
}

ดังนั้นฉันจะพูดตรงข้ามกับสิ่งที่ V0ldek ตอบและนั่นคือ "ข้อผิดพลาด (ถ้าเป็นข้อบกพร่องจริงๆ) มีแนวโน้มมากที่สุดในคอมไพเลอร์ Roslyn และ. NET Core"

อีกเหตุผลหนึ่งที่เชื่อว่านั่นคือผลลัพธ์ของผลลัพธ์การคำนวณที่ไม่ได้ตรวจสอบครั้งแรกนั้นเหมือนกันสำหรับทุกคนและเป็นค่าที่เกินมูลค่าสูงสุดของUInt32ประเภท

Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale) - UInt32.MaxValue - 1)); // 859091763

ลบหนึ่งอยู่ตรงนั้นขณะที่เราเริ่มจากศูนย์ซึ่งเป็นค่าที่ยากต่อการลบตัวเอง หากความเข้าใจทางคณิตศาสตร์ของฉันเกี่ยวกับการโอเวอร์โฟลว์นั้นถูกต้องเราจะเริ่มจากจำนวนถัดไปหลังจากค่าสูงสุด

UPDATE

ตามความคิดเห็น jalsh

7.0 เป็น double ไม่ใช่ float ลอง 7.0f มันจะยังคงให้ 0

ความคิดเห็นของเขาถูกต้อง ในกรณีที่เราใช้ float คุณยังได้รับ 0 สำหรับ Roslyn และ. NET Core แต่ในทางกลับกันโดยใช้ผลลัพธ์สองเท่าใน 7

ฉันได้ทำการทดสอบเพิ่มเติมและสิ่งต่าง ๆ ก็ยิ่งเลวร้ายลง แต่ในที่สุดทุกอย่างก็สมเหตุสมผล (อย่างน้อยสักนิด)

สิ่งที่ฉันถือว่าเป็น. NET Framework 4.7.2 คอมไพเลอร์ (เปิดตัวในช่วงกลางปี ​​2018) ใช้การเพิ่มประสิทธิภาพที่แตกต่างจากคอมไพเลอร์. NET Core 3.1 และ Roslyn 3.4 (ออกเมื่อสิ้นปี 2019) การเพิ่มประสิทธิภาพ / การคำนวณที่แตกต่างกันเหล่านี้ใช้สำหรับค่าคงที่ที่ทราบ ณ เวลารวบรวม นั่นคือเหตุผลที่มีความจำเป็นต้องใช้uncheckedคำสำคัญเนื่องจากคอมไพเลอร์รู้อยู่แล้วว่ามีเหตุการณ์ล้นเกิดขึ้น แต่การคำนวณที่แตกต่างกันนั้นถูกใช้เพื่อปรับ IL ขั้นสุดท้ายให้เหมาะสม

ซอร์สโค้ดเดียวกันและ IL เดียวกันเกือบทั้งหมดยกเว้นคำสั่ง IL_000a หนึ่งคอมไพเลอร์คำนวณ 7 และ 0 อื่น ๆ

รหัสแหล่งที่มา

using System;

public class Program
{
    const float scale = 64 * 1024;

    public static void Main()
    {
        Console.WriteLine(unchecked((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)));
        Console.WriteLine(unchecked((uint)(scale * scale + 7.0)));
    }
}

.NET Framework (x64) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Fields
    .field private static literal float32 scale = float32(65536)

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldc.i4 859091763
        IL_0005: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_000a: ldc.i4.7
        IL_000b: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0010: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2062
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

} // end of class Program

สาขาคอมไพเลอร์ของ Roslyn (ก.ย. 2019) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [System.Private.CoreLib]System.Object
{
    // Fields
    .field private static literal float32 scale = float32(65536)

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 17 (0x11)
        .maxstack 8

        IL_0000: ldc.i4 859091763
        IL_0005: call void [System.Console]System.Console::WriteLine(uint32)
        IL_000a: ldc.i4.0
        IL_000b: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0010: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2062
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

} // end of class Program

มันเริ่มต้นอย่างถูกต้องเมื่อคุณเพิ่มนิพจน์ที่ไม่คงที่ (โดยค่าเริ่มต้นunchecked) ตามด้านล่าง

using System;

public class Program
{
    static Random random = new Random();

    public static void Main()
    {
        var scale = 64 * random.Next(1024, 1025);       
        uint f = (uint)(ulong)(scale * scale + 7f);
        uint d = (uint)(ulong)(scale * scale + 7d);
        uint i = (uint)(ulong)(scale * scale + 7);

        Console.WriteLine((uint)(ulong)(1.2 * scale * scale + 1.5 * scale)); // 859091763
        Console.WriteLine((uint)(ulong)(scale * scale + 7f)); // 7
        Console.WriteLine(f); // 7
        Console.WriteLine((uint)(ulong)(scale * scale + 7d)); // 7
        Console.WriteLine(d); // 7
        Console.WriteLine((uint)(ulong)(scale * scale + 7)); // 7
        Console.WriteLine(i); // 7
    }
}

ซึ่งสร้าง IL ที่เหมือนกันทุกประการโดยคอมไพเลอร์ทั้งคู่

.NET Framework (x64) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Fields
    .field private static class [mscorlib]System.Random random

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 164 (0xa4)
        .maxstack 4
        .locals init (
            [0] int32,
            [1] uint32,
            [2] uint32
        )

        IL_0000: ldc.i4.s 64
        IL_0002: ldsfld class [mscorlib]System.Random Program::random
        IL_0007: ldc.i4 1024
        IL_000c: ldc.i4 1025
        IL_0011: callvirt instance int32 [mscorlib]System.Random::Next(int32, int32)
        IL_0016: mul
        IL_0017: stloc.0
        IL_0018: ldloc.0
        IL_0019: ldloc.0
        IL_001a: mul
        IL_001b: conv.r4
        IL_001c: ldc.r4 7
        IL_0021: add
        IL_0022: conv.u8
        IL_0023: conv.u4
        IL_0024: ldloc.0
        IL_0025: ldloc.0
        IL_0026: mul
        IL_0027: conv.r8
        IL_0028: ldc.r8 7
        IL_0031: add
        IL_0032: conv.u8
        IL_0033: conv.u4
        IL_0034: stloc.1
        IL_0035: ldloc.0
        IL_0036: ldloc.0
        IL_0037: mul
        IL_0038: ldc.i4.7
        IL_0039: add
        IL_003a: conv.i8
        IL_003b: conv.u4
        IL_003c: stloc.2
        IL_003d: ldc.r8 1.2
        IL_0046: ldloc.0
        IL_0047: conv.r8
        IL_0048: mul
        IL_0049: ldloc.0
        IL_004a: conv.r8
        IL_004b: mul
        IL_004c: ldc.r8 1.5
        IL_0055: ldloc.0
        IL_0056: conv.r8
        IL_0057: mul
        IL_0058: add
        IL_0059: conv.u8
        IL_005a: conv.u4
        IL_005b: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0060: ldloc.0
        IL_0061: ldloc.0
        IL_0062: mul
        IL_0063: conv.r4
        IL_0064: ldc.r4 7
        IL_0069: add
        IL_006a: conv.u8
        IL_006b: conv.u4
        IL_006c: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0071: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0076: ldloc.0
        IL_0077: ldloc.0
        IL_0078: mul
        IL_0079: conv.r8
        IL_007a: ldc.r8 7
        IL_0083: add
        IL_0084: conv.u8
        IL_0085: conv.u4
        IL_0086: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_008b: ldloc.1
        IL_008c: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_0091: ldloc.0
        IL_0092: ldloc.0
        IL_0093: mul
        IL_0094: ldc.i4.7
        IL_0095: add
        IL_0096: conv.i8
        IL_0097: conv.u4
        IL_0098: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_009d: ldloc.2
        IL_009e: call void [mscorlib]System.Console::WriteLine(uint32)
        IL_00a3: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2100
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

    .method private hidebysig specialname rtspecialname static 
        void .cctor () cil managed 
    {
        // Method begins at RVA 0x2108
        // Code size 11 (0xb)
        .maxstack 8

        IL_0000: newobj instance void [mscorlib]System.Random::.ctor()
        IL_0005: stsfld class [mscorlib]System.Random Program::random
        IL_000a: ret
    } // end of method Program::.cctor

} // end of class Program

สาขาคอมไพเลอร์ของ Roslyn (ก.ย. 2019) IL

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [System.Private.CoreLib]System.Object
{
    // Fields
    .field private static class [System.Private.CoreLib]System.Random random

    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 164 (0xa4)
        .maxstack 4
        .locals init (
            [0] int32,
            [1] uint32,
            [2] uint32
        )

        IL_0000: ldc.i4.s 64
        IL_0002: ldsfld class [System.Private.CoreLib]System.Random Program::random
        IL_0007: ldc.i4 1024
        IL_000c: ldc.i4 1025
        IL_0011: callvirt instance int32 [System.Private.CoreLib]System.Random::Next(int32, int32)
        IL_0016: mul
        IL_0017: stloc.0
        IL_0018: ldloc.0
        IL_0019: ldloc.0
        IL_001a: mul
        IL_001b: conv.r4
        IL_001c: ldc.r4 7
        IL_0021: add
        IL_0022: conv.u8
        IL_0023: conv.u4
        IL_0024: ldloc.0
        IL_0025: ldloc.0
        IL_0026: mul
        IL_0027: conv.r8
        IL_0028: ldc.r8 7
        IL_0031: add
        IL_0032: conv.u8
        IL_0033: conv.u4
        IL_0034: stloc.1
        IL_0035: ldloc.0
        IL_0036: ldloc.0
        IL_0037: mul
        IL_0038: ldc.i4.7
        IL_0039: add
        IL_003a: conv.i8
        IL_003b: conv.u4
        IL_003c: stloc.2
        IL_003d: ldc.r8 1.2
        IL_0046: ldloc.0
        IL_0047: conv.r8
        IL_0048: mul
        IL_0049: ldloc.0
        IL_004a: conv.r8
        IL_004b: mul
        IL_004c: ldc.r8 1.5
        IL_0055: ldloc.0
        IL_0056: conv.r8
        IL_0057: mul
        IL_0058: add
        IL_0059: conv.u8
        IL_005a: conv.u4
        IL_005b: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0060: ldloc.0
        IL_0061: ldloc.0
        IL_0062: mul
        IL_0063: conv.r4
        IL_0064: ldc.r4 7
        IL_0069: add
        IL_006a: conv.u8
        IL_006b: conv.u4
        IL_006c: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0071: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0076: ldloc.0
        IL_0077: ldloc.0
        IL_0078: mul
        IL_0079: conv.r8
        IL_007a: ldc.r8 7
        IL_0083: add
        IL_0084: conv.u8
        IL_0085: conv.u4
        IL_0086: call void [System.Console]System.Console::WriteLine(uint32)
        IL_008b: ldloc.1
        IL_008c: call void [System.Console]System.Console::WriteLine(uint32)
        IL_0091: ldloc.0
        IL_0092: ldloc.0
        IL_0093: mul
        IL_0094: ldc.i4.7
        IL_0095: add
        IL_0096: conv.i8
        IL_0097: conv.u4
        IL_0098: call void [System.Console]System.Console::WriteLine(uint32)
        IL_009d: ldloc.2
        IL_009e: call void [System.Console]System.Console::WriteLine(uint32)
        IL_00a3: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2100
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

    .method private hidebysig specialname rtspecialname static 
        void .cctor () cil managed 
    {
        // Method begins at RVA 0x2108
        // Code size 11 (0xb)
        .maxstack 8

        IL_0000: newobj instance void [System.Private.CoreLib]System.Random::.ctor()
        IL_0005: stsfld class [System.Private.CoreLib]System.Random Program::random
        IL_000a: ret
    } // end of method Program::.cctor

} // end of class Program

ดังนั้นในที่สุดฉันเชื่อว่าสาเหตุของพฤติกรรมที่แตกต่างกันเป็นเพียงกรอบรุ่นที่แตกต่างกันและ / หรือคอมไพเลอร์ที่ใช้การเพิ่มประสิทธิภาพ / การคำนวณที่แตกต่างกันสำหรับการแสดงออกอย่างต่อเนื่อง แต่ในกรณีอื่น ๆ พฤติกรรมจะเหมือนกันมาก


7.0 เป็น double ไม่ใช่ float ลอง 7.0f มันจะยังให้ 0
jalsh

ใช่มันควรเป็นประเภทจุดลอยตัวไม่ใช่ลอยตัว ขอบคุณสำหรับการแก้ไข
dropoutcoder

การเปลี่ยนแปลงมุมมองทั้งหมดของปัญหาเมื่อจัดการกับความแม่นยำสองเท่าที่คุณได้รับนั้นสูงกว่ามากและผลลัพธ์ที่อธิบายไว้ในคำตอบของ V0ldek เปลี่ยนไปอย่างมากคุณอาจแค่เปลี่ยนสเกลเป็นสองเท่าและตรวจสอบอีกครั้งผลลัพธ์จะเหมือนเดิม ..
jalsh

ในท้ายที่สุดมันเป็นปัญหาที่ซับซ้อนมากขึ้น
dropoutcoder

1
@jalsh ใช่ แต่มีธงคอมไพเลอร์ที่เปลี่ยนบริบทการตรวจสอบทุกที่ คุณอาจต้องการตรวจสอบทุกอย่างเพื่อความปลอดภัยยกเว้นเส้นทางร้อนที่ต้องการรอบ CPU ทั้งหมดที่สามารถรับได้
V0ldek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.