Random Integer 64 in Range のバグ??

上から1段目のノードだと表記通りMinとMaxの間の数からランダムで数が出力されます。しかし2段目のノードはMinがMaxよりも一桁少ないんですが、-1147…のように上限値になったときみたいな表記になります。どうやらMinがMaxよりも桁が少ないとこうなるようです。

3段目と4段目は普通の8bit Integerの上限範囲内で実験してみたのですが通常通りに出力されました。

「これはバグですか?」と質問しても、いつも私の勘違いで終わることが多いのですが、これは今度こそバグでしょうか?

screenshot. (63)

ちなみにバージョンは5.21です!

header

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CustomMath.generated.h"

/**
 * 
 */
UCLASS()
class YOUR_API UCustomMath : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()	
	UFUNCTION(BlueprintCallable)
	static int64 RandomRangeInt64(int64 min, int64 max);
};

cpp

#include "CustomMath.h"
#include <random>

int64 UCustomMath::RandomRangeInt64(int64 min, int64 max) 
{	
	std::random_device rd;
	std::mt19937 rng(rd());
	std::uniform_int_distribution<int64> uni(min, max);
	auto random_integer = uni(rng);
	return random_integer;
}

こんにちは
RandHelper64でオーバーフローが起きています

UnrealMathUtility.hを見ると以下のような実装が見つかります

UE_NODISCARD static FORCEINLINE int64 RandHelper64(int64 A)
{
	// Note that on some platforms RAND_MAX is a large number so we cannot do ((rand()/(RAND_MAX+1)) * A)
	// or else we may include the upper bound results, which should be excluded.
	return A > 0 ? Min<int64>(TruncToInt(FRand() * (float)A), A - 1) : 0;
}

ここで、GenericPlatformMath.hでは、TruncToIntという関数は以下のように実装されています

static constexpr FORCEINLINE int32 TruncToInt32(float F)
{
	return (int32)F;
}
static constexpr FORCEINLINE int32 TruncToInt32(double F)
{
	return (int32)F;
}
static constexpr FORCEINLINE int64 TruncToInt64(double F)
{
	return (int64)F;
}

static constexpr FORCEINLINE int32 TruncToInt(float F) { return TruncToInt32(F); }
static constexpr FORCEINLINE int64 TruncToInt(double F) { return TruncToInt64(F); }

TruncToInt(float)を見ると、TruncToInt32()を呼び出しているため、この戻り値のビット数が足りずにオーバーフロー発生となります

(このコードはインライン実装のため、念のため手元でコピペしてデバッガーツールも使用してみました)

結論、エンジンのバグですね

unreal issuesも検索したところUE-193898が見つかりました
UE5.4で修正予定らしいです

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.